PySpark برنامج تعليمي للمبتدئين: تعلم مع الأمثلة
⚡ ملخص ذكي
PySpark هي Python واجهة برمجة التطبيقات (API) لـ Apache Sparkيتيح ذلك للمحللين تشغيل معالجة البيانات الموزعة، واستعلامات SQL، والتعلم الآلي على مجموعات الحواسيب. يشرح هذا الدليل كيفية تثبيته. Sparkثم يقوم Context و SQLContext ببناء مصنف الانحدار اللوجستي.

قبل تعلم PySpark، فلنفهم:
ما هو اباتشي Spark?
Spark هو حل للبيانات الضخمة ثبت أنه أسهل وأسرع من Hadoop MapReduce. Spark هو برنامج مفتوح المصدر تم تطويره بواسطة مختبر UC Berkeley RAD في عام 2009. ومنذ طرحه للجمهور في عام 2010، Spark نمت شعبيتها ويتم استخدامها من خلال الصناعة على نطاق غير مسبوق.
في عصر البيانات الضخمة، يحتاج الممارسون أكثر من أي وقت مضى إلى أدوات سريعة وموثوقة لمعالجة تدفق البيانات. كانت الأدوات السابقة مثل MapReduce شائعة الاستخدام، لكنها كانت بطيئة. وللتغلب على هذه المشكلة، Spark يقدم حلاً سريعًا للأغراض العامة. الفرق الرئيسي بين Spark وMapReduce هو ذلك Spark يقوم بإجراء العمليات الحسابية في الذاكرة أثناء تشغيلها على القرص الصلب. وهو يسمح بالوصول إلى البيانات ومعالجتها بسرعة عالية، مما يقلل الوقت من ساعات إلى دقائق.
ما هو بيSpark?
PySpark هي أداة تم إنشاؤها بواسطة أباتشي Spark مجتمع للاستخدام Python مع Spark. يسمح بالعمل مع RDD (مجموعة البيانات الموزعة المرنة) في Python. كما يقدم PySpark شل للارتباط Python واجهات برمجة التطبيقات مع Spark الأساسية للبدء Spark سياق الكلام. Spark هو اسم المحرك لتحقيق الحوسبة العنقودية، في حين أن PySpark is Pythonمكتبة للاستخدام Spark.
تُشحن المكتبة على شكل pyspark حزمة على PyPI، لذا واحدة pip install pyspark يستعين بمحرك Scala/JVM بالإضافة إلى جسر Py4J الذي يسمح Python تستدعي الكائنات هذه الحزمة. وكل ما يليها يعتمد على تلك الحزمة.
كيف Spark العمل؟
Spark يعتمد هذا النظام على محرك حسابي، أي أنه يتولى جدولة المهام وتوزيعها ومراقبة التطبيق. تُنفذ كل مهمة عبر عدة أجهزة عاملة تُسمى مجموعة الحوسبة. تشير مجموعة الحوسبة إلى تقسيم المهام؛ حيث يقوم جهاز واحد بتنفيذ مهمة معينة، بينما تُساهم الأجهزة الأخرى في الناتج النهائي من خلال مهام مختلفة. في النهاية، تُجمع جميع المهام لإنتاج الناتج النهائي. Spark المشرف يعطي نظرة عامة 360 لمختلف Spark وظائف.
يوضح الرسم البياني أدناه كيف يقوم برنامج التشغيل بتوزيع العمل على أجهزة العمل التي تشكل مثل هذه المجموعة.
كيف Spark للعمل
Spark صمم للعمل مع
- Python
- Java
- سكالا
- SQL
سمة هامة من Spark وهي عبارة عن كمية هائلة من المكتبات المدمجة، بما في ذلك MLlib للتعلم الآلي. Spark كما أنه مصمم للعمل مع مجموعات Hadoop ويمكنه قراءة أنواع واسعة من الملفات، بما في ذلك بيانات Hive وCSV وJSON. Cassandra البيانات من بين أمور أخرى.
لماذا استخدام Spark?
بصفتك ممارسًا مستقبليًا للبيانات، يجب أن تكون على دراية بـ Pythonمكتبات 's الشهيرة: باندا و تعلم الحروفتُعدّ هاتان المكتبتان رائعتين لاستكشاف مجموعات البيانات متوسطة الحجم. وتُبنى مشاريع التعلّم الآلي الاعتيادية وفق المنهجية التالية:
- تحميل البيانات إلى القرص
- استيراد البيانات إلى ذاكرة الجهاز
- معالجة/تحليل البيانات
- بناء نموذج التعلم الآلي
- قم بتخزين التنبؤ مرة أخرى على القرص
تظهر المشكلة عندما يرغب عالم البيانات في معالجة بيانات ضخمة جدًا بحيث لا يستطيع جهاز كمبيوتر واحد معالجتها. في بدايات علم البيانات، كان الممارسون يختارون عينة عشوائية من البيانات، إذ لم تكن هناك حاجة دائمة للتدريب على مجموعات بيانات ضخمة. كان عالم البيانات يجد عينة إحصائية جيدة، ويُجري اختبارًا إضافيًا للتحقق من متانة النموذج، ثم يتوصل إلى نموذج ممتاز.
ومع ذلك، هناك بعض المشاكل مع هذا:
- هل تعكس مجموعة البيانات العالم الحقيقي؟
- هل تتضمن البيانات مثالاً محددًا؟
- هل النموذج مناسب لأخذ العينات؟
خذ توصية المستخدمين على سبيل المثال. يعتمد مقدمو التوصيات على مقارنة المستخدمين مع المستخدمين الآخرين في تقييم تفضيلاتهم. إذا أخذ ممارس البيانات مجموعة فرعية فقط من البيانات، فلن يكون هناك مجموعة من المستخدمين المتشابهين جدًا مع بعضهم البعض. يحتاج مقدمو التوصيات إلى العمل على مجموعة البيانات الكاملة أو عدم العمل على الإطلاق.
ماهو الحل؟
كان الحل واضحًا منذ فترة طويلة، وهو تقسيم المشكلة إلى أجهزة كمبيوتر متعددة. كما أن الحوسبة المتوازية تأتي مع مشاكل متعددة. غالبًا ما يواجه المطورون مشكلة في كتابة التعليمات البرمجية المتوازية وينتهي بهم الأمر إلى حل مجموعة من المشكلات المعقدة المتعلقة بالمعالجة المتعددة نفسها.
PySpark يُوفر هذا البرنامج لعالم البيانات واجهة برمجة تطبيقات (API) يمكن استخدامها لحل مشاكل معالجة البيانات المتوازية. بايثونSpark يتعامل مع تعقيدات المعالجة المتعددة، مثل توزيع البيانات، وتوزيع التعليمات البرمجية، وجمع المخرجات من العمال على مجموعة من الأجهزة.
Spark يمكن تشغيله بشكل مستقل ولكن غالبًا ما يتم تشغيله أعلى إطار عمل حوسبة عنقودية مثل Hadoop. ومع ذلك، في الاختبار والتطوير، يمكن لعالم البيانات تشغيله بكفاءة Spark على صناديق التطوير الخاصة بهم أو أجهزة الكمبيوتر المحمولة التي لا تحتوي على مجموعة
- واحدة من المزايا الرئيسية ل Spark يتمثل الهدف في بناء بنية تتضمن إدارة تدفق البيانات، واستعلامات البيانات بسلاسة، والتنبؤ بالتعلم الآلي، والوصول في الوقت الفعلي إلى التحليلات المختلفة.
- Spark يعمل بشكل وثيق مع SQL اللغة، أي البيانات المهيكلة. وهي تتيح الاستعلام عن البيانات في الوقت الفعلي.
- تتمثل المهمة الرئيسية لعالم البيانات في تحليل البيانات وبناء نماذج تنبؤية. باختصار، يحتاج عالم البيانات إلى معرفة كيفية الاستعلام عن البيانات باستخدام لغة SQL، وإعداد التقارير الإحصائية، والاستفادة من تقنيات التعلم الآلي لإنتاج التنبؤات. يقضي عالم البيانات جزءًا كبيرًا من وقته في تنظيف البيانات وتحويلها وتحليلها. بمجرد أن تصبح مجموعة البيانات أو سير عمل البيانات جاهزًا، يستخدم عالم البيانات تقنيات متنوعة لاكتشاف الرؤى والأنماط الخفية. يجب أن تكون عملية معالجة البيانات قوية وسهلة الاستخدام في الوقت نفسه. Spark هي الأداة المناسبة بفضل سرعتها وواجهات برمجة التطبيقات الغنية بها.
في هذا بايSpark البرنامج التعليمي، سوف تتعلم كيفية بناء مصنف مع PySpark أمثلة.
كيفية تثبيت PySpark مع AWS
استخدم Jupyter يقوم الفريق ببناء صورة Docker للتشغيل Spark بكفاءة. فيما يلي الخطوات التي يمكنك اتباعها لتثبيت PySpark مثيل في AWS.
الرجوع إلى البرنامج التعليمي لدينا على AWS و TensorFlow
الخطوة 1: إنشاء مثيل
أولا وقبل كل شيء، تحتاج إلى إنشاء مثيل. انتقل إلى حساب AWS الخاص بك وقم بتشغيل المثيل. يمكنك زيادة مساحة التخزين حتى 15 جرامًا واستخدام نفس مجموعة الأمان كما في البرنامج التعليمي TensorFlow.
الخطوة 2: افتح الاتصال
افتح الاتصال وقم بتثبيت حاوية Docker. لمزيد من التفاصيل، راجع البرنامج التعليمي مع TensorFlow مع عامل في حوض السفن. لاحظ أنه يجب أن تكون في دليل العمل الصحيح.
ما عليك سوى تشغيل هذه الرموز لتثبيت Docker:
sudo yum update -y sudo yum install -y docker sudo service docker start sudo user-mod -a -G docker ec2-user exit
الخطوة 3: أعد فتح الاتصال والتثبيت Spark
بعد إعادة فتح الاتصال، يمكنك تثبيت الصورة التي تحتوي على PySpark.
## Spark docker run -v ~/work:/home/jovyan/work -d -p 8888:8888 jupyter/pyspark-notebook ## Allow preserving Jupyter notebook sudo chown 1000 ~/work ## Install tree to see our working directory next sudo yum install -y tree
الخطوة 4: مفتوح Jupyter
تحقق من الحاوية واسمها
docker ps
قم بتشغيل عامل الإرساء باستخدام سجلات عامل الإرساء متبوعة باسم عامل الإرساء. على سبيل المثال، يقوم عامل الإرساء بتسجيل zealous_goldwasser
انتقل إلى المتصفح الخاص بك وابدأ Jupyter. العنوان هو http://localhost:8888/. الصق كلمة المرور التي قدمتها المحطة.
ملاحظة: إذا كنت ترغب في تحميل/تنزيل ملف إلى جهاز AWS الخاص بك، يمكنك استخدام البرنامج Cyberduck.
كيفية تثبيت PySpark on Windows/ ماك مع كوندا
فيما يلي عملية مفصلة حول كيفية تثبيت PySpark on Windows/ ماك باستخدام أناكوندا:
لتثبيت Spark على جهازك المحلي، من الممارسات الموصى بها إنشاء بيئة كوندا جديدة. سيتم تثبيت هذه البيئة الجديدة Python 3.6 Spark وجميع التبعيات.
مستخدم Mac
cd anaconda3 touch hello-spark.yml vi hello-spark.yml
Windows اسم المستخدم
cd C:\Users\Admin\Anaconda3 echo.>hello-spark.yml notepad hello-spark.yml
يمكنك تحرير ملف .yml. كن حذرا مع المسافة البادئة. مطلوب مسافتين قبل –
name: hello-spark
dependencies:
- python=3.6
- jupyter
- ipython
- numpy
- numpy-base
- pandas
- py4j
- pyspark
- pytz
احفظه وأنشئ البيئة. إنه يستغرق بعض الوقت
conda env create -f hello-spark.yml
لمزيد من التفاصيل حول الموقع، يرجى مراجعة البرنامج التعليمي تثبيت TensorFlow
يمكنك التحقق من كافة البيئة المثبتة في جهازك
conda env list
Activate hello-spark
مستخدم Mac
source activate hello-spark
Windows اسم المستخدم
activate hello-spark
ملاحظة: لقد قمت بالفعل بإنشاء بيئة TensorFlow محددة لتشغيل البرامج التعليمية على TensorFlow. يعد إنشاء بيئة جديدة مختلفة عن hello-tf أكثر ملاءمة. ليس من المنطقي التحميل الزائد لـ hello-tf Spark أو أي مكتبات أخرى للتعلم الآلي.
تخيل أن معظم مشروعك يتضمن TensorFlow، لكنك تحتاج إلى استخدامه Spark لمشروع واحد معين. يمكنك تعيين بيئة TensorFlow لكل مشروعك وإنشاء بيئة منفصلة له Spark. يمكنك إضافة أكبر عدد ممكن من المكتبات في Spark البيئة كما تريد دون التدخل في بيئة TensorFlow. بمجرد الانتهاء من ذلك Sparkمشروع، يمكنك محوه دون التأثير على بيئة TensorFlow.
Jupyter
ساعات العمل Jupyter دفتر الملاحظات وحاول إذا PySpark يعمل. في دفتر ملاحظات جديد، قم بلصق ملف Py التاليSpark عينة من الرموز:
import pyspark from pyspark import SparkContext sc =SparkContext()
لا ينتج عن التشغيل الناجح أي مخرجات على الإطلاق، كما توضح لقطة الشاشة لدفتر الملاحظات أدناه.
إذا ظهر خطأ، فمن المرجح أن Java لم يتم تثبيته على جهازك. في نظام التشغيل Mac، افتح المحطة الطرفية واكتب java -version، إذا كان هناك إصدار java، فتأكد من أنه 1.8. Windows، انتقل إلى التطبيق وتحقق مما إذا كان هناك Java المجلد. إذا كان هناك أ Java المجلد، والتحقق من ذلك Java تم تثبيت الإصدار 1.8. وحتى وقت كتابة هذا التقرير، فإن PySpark غير متوافق مع Java 9 وما فوق.
ملاحظة حول الإصدار: أن Java ينطبق القيد رقم 8 على Spark تم استخدام الإصدار 2.x في جميع مراحل هذا الشرح. الإصدار الحالي Spark تعمل الإصدارات 3.x و 4.x على Java الإصدارات 8 و11 و17، لذا فإن استخدام إصدار أحدث من JDK مناسب إذا قمت بتثبيت إصدار متوافق من PySpark الإصدار.
إذا كنت بحاجة إلى تثبيت Java، عليك أن تفكر الصفحة وتحميل jdk-8u181-windows-x64.exe
بالنسبة لمستخدمي Mac، يوصى باستخدام "brew".
brew tap caskroom/versions brew cask install java8
الرجوع إلى هذا البرنامج التعليمي خطوة بخطوة على كيفية تثبيت Java
ملاحظة: استخدم خاصية الإزالة لمسح بيئة كاملة.
conda env remove -n hello-spark -y
Spark السياق
Sparkالسياق هو المحرك الداخلي الذي يسمح بالاتصالات مع المجموعات. إذا كنت تريد تشغيل عملية، فأنت بحاجة إلى Sparkسياق الكلام.
إنشاء Sparkالسياق
بادئ ذي بدء، تحتاج إلى بدء Sparkسياق الكلام.
import pyspark from pyspark import SparkContext sc =SparkContext()
الآن وبعد أن Sparkالسياق جاهز، يمكنك إنشاء مجموعة من البيانات تسمى RDD، Resilient Distributed Dataset. تتم العمليات الحسابية في RDD بشكل متوازي تلقائيًا عبر المجموعة.
nums= sc.parallelize([1,2,3,4])
يمكنك الوصول إلى الصف الأول باستخدام اللقطة
nums.take(1)
[1]
يمكنك تطبيق تحويل على البيانات باستخدام دالة لامدا. في بايSpark المثال أدناه، تقوم بإرجاع مربع الأعداد. إنه تحول الخريطة
squared = nums.map(lambda x: x*x).collect() for num in squared: print('%i ' % (num))
1 4 9 16
SQLContext
الطريقة الأكثر ملاءمة هي استخدام DataFrame. Sparkتم تحديد السياق مسبقًا، ويمكنك استخدامه لإنشاء DataFrame. ستحتاج أيضًا إلى تعريف SQLContext.
يسمح SQLContext بتوصيل المحرك بمصادر بيانات مختلفة. يتم استخدامه لبدء وظائف Spark SQL.
ملاحظة حول الإصدار: تم استبدال SQLContext بواسطة Sparkالجلسة في Spark 2.0 وتم إيقاف استخدامها رسميًا في Spark 3.0. تحتفظ الأمثلة أدناه بـ SQLContext لأن هذا ما يتم تشغيل الشرح الأصلي عليه؛ في مجموعة حديثة، تكون نقطة الدخول المكافئة هي SparkSession.builder.getOrCreate()، مما يكشف عن نفس طرق القراءة وإنشاء DataFrame.
from pyspark.sql import Row from pyspark.sql import SQLContext sqlContext = SQLContext(sc)
الآن في هذا Spark البرنامج التعليمي Python، فلنقم بإنشاء قائمة من الصفوف. ستحتوي كل صف على اسم الأشخاص وأعمارهم. مطلوب أربع خطوات:
الخطوة 1) قم بإنشاء قائمة Tuple بالمعلومات
[('John',19),('Smith',29),('Adam',35),('Henry',50)]
الخطوة 2) بناء RDD
rdd = sc.parallelize(list_p)
الخطوة 3) تحويل الصفوف
rdd.map(lambda x: Row(name=x[0], age=int(x[1])))
الخطوة 4) إنشاء سياق DataFrame
sqlContext.createDataFrame(ppl) list_p = [('John',19),('Smith',29),('Adam',35),('Henry',50)] rdd = sc.parallelize(list_p) ppl = rdd.map(lambda x: Row(name=x[0], age=int(x[1]))) DF_ppl = sqlContext.createDataFrame(ppl)
إذا كنت تريد الوصول إلى نوع كل ميزة، فيمكنك استخدام printSchema()
DF_ppl.printSchema() root |-- age: long (nullable = true) |-- name: string (nullable = true)
مثال للتعلم الآلي مع PySpark
والآن بعد أن أصبحت لديك فكرة مختصرة عن Spark وSQLContext، أنت جاهز لإنشاء أول برنامج للتعلم الآلي.
فيما يلي الخطوات اللازمة لبناء برنامج التعلم الآلي باستخدام PySpark:
- الخطوة 1) العمليات الأساسية مع PySpark
- الخطوة 2) المعالجة المسبقة للبيانات
- الخطوة 3) بناء خط أنابيب معالجة البيانات
- الخطوة 4) بناء المصنف: لوجستي
- الخطوة 5) تدريب النموذج وتقييمه
- الخطوة 6) ضبط المعلمة الفائقة
في هذا بايSpark في هذا الدرس التعليمي حول تعلم الآلة، سنستخدم مجموعة بيانات البالغين. والهدف من هذا الدرس هو تعلم كيفية استخدام لغة بايثون (Py).Sparkللحصول على مزيد من المعلومات حول مجموعة البيانات، راجع هذا البرنامج التعليمي.
لاحظ أن مجموعة البيانات ليست مهمة وقد تعتقد أن الحساب يستغرق وقتًا طويلاً. Spark تم تصميمه لمعالجة كمية كبيرة من البيانات. Sparkيتحسن أداء هذه المكتبة مقارنة بمكتبات التعلم الآلي الأخرى عندما تكبر مجموعة البيانات التي تتم معالجتها.
الخطوة 1) العمليات الأساسية مع PySpark
أولا وقبل كل شيء، تحتاج إلى تهيئة SQLContext الذي لم يبدأ بالفعل بعد.
#from pyspark.sql import SQLContext url = "https://raw.githubusercontent.com/guru99-edu/R-Programming/master/adult_data.csv" from pyspark import SparkFiles sc.addFile(url) sqlContext = SQLContext(sc)
وبعد ذلك، يمكنك قراءة ملف السيرة الذاتية باستخدام sqlContext.read.csv. يمكنك استخدام inferSchema المعين على True to say Spark لتخمين نوع البيانات تلقائيا. بشكل افتراضي، يتم تشغيله إلى False.
df = sqlContext.read.csv(SparkFiles.get("adult_data.csv"), header=True, inferSchema= True)
دعونا نلقي نظرة على نوع البيانات
df.printSchema() root |-- age: integer (nullable = true) |-- workclass: string (nullable = true) |-- fnlwgt: integer (nullable = true) |-- education: string (nullable = true) |-- education_num: integer (nullable = true) |-- marital: string (nullable = true) |-- occupation: string (nullable = true) |-- relationship: string (nullable = true) |-- race: string (nullable = true) |-- sex: string (nullable = true) |-- capital_gain: integer (nullable = true) |-- capital_loss: integer (nullable = true) |-- hours_week: integer (nullable = true) |-- native_country: string (nullable = true) |-- label: string (nullable = true)
يمكنك رؤية البيانات مع العرض.
df.show(5, truncate = False)
+---+----------------+------+---------+-------------+------------------+-----------------+-------------+-----+------+------------+------------+----------+--------------+-----+ |age|workclass |fnlwgt|education|education_num|marital |occupation |relationship |race |sex |capital_gain|capital_loss|hours_week|native_country|label| +---+----------------+------+---------+-------------+------------------+-----------------+-------------+-----+------+------------+------------+----------+--------------+-----+ |39 |State-gov |77516 |Bachelors|13 |Never-married |Adm-clerical |Not-in-family|White|Male |2174 |0 |40 |United-States |<=50K| |50 |Self-emp-not-inc|83311 |Bachelors|13 |Married-civ-spouse|Exec-managerial |Husband |White|Male |0 |0 |13 |United-States |<=50K| |38 |Private |215646|HS-grad |9 |Divorced |Handlers-cleaners|Not-in-family|White|Male |0 |0 |40 |United-States |<=50K| |53 |Private |234721|11th |7 |Married-civ-spouse|Handlers-cleaners|Husband |Black|Male |0 |0 |40 |United-States |<=50K| |28 |Private |338409|Bachelors|13 |Married-civ-spouse|Prof-specialty |Wife |Black|Female|0 |0 |40 |Cuba |<=50K| +---+----------------+------+---------+-------------+------------------+-----------------+-------------+-----+------+------------+------------+----------+--------------+-----+ only showing top 5 rows
إذا لم تقم بتعيين قيمة inferSchema إلى True، فإليك ما يحدث للنوع. جميعها من نوع سلسلة نصية.
df_string = sqlContext.read.csv(SparkFiles.get("adult.csv"), header=True, inferSchema= False) df_string.printSchema() root |-- age: string (nullable = true) |-- workclass: string (nullable = true) |-- fnlwgt: string (nullable = true) |-- education: string (nullable = true) |-- education_num: string (nullable = true) |-- marital: string (nullable = true) |-- occupation: string (nullable = true) |-- relationship: string (nullable = true) |-- race: string (nullable = true) |-- sex: string (nullable = true) |-- capital_gain: string (nullable = true) |-- capital_loss: string (nullable = true) |-- hours_week: string (nullable = true) |-- native_country: string (nullable = true) |-- label: string (nullable = true)
لتحويل المتغير المستمر إلى التنسيق الصحيح، يمكنك استخدام إعادة صياغة الأعمدة. يمكنك استخدام withColumn لمعرفة ذلك Spark أي عمود سيتم تشغيل التحويل عليه؟
# Import all from `sql.types` from pyspark.sql.types import * # Write a custom function to convert the data type of DataFrame columns def convertColumn(df, names, newType): for name in names: df = df.withColumn(name, df[name].cast(newType)) return df # List of continuous features CONTI_FEATURES = ['age', 'fnlwgt','capital_gain', 'education_num', 'capital_loss', 'hours_week'] # Convert the type df_string = convertColumn(df_string, CONTI_FEATURES, FloatType()) # Check the dataset df_string.printSchema() root |-- age: float (nullable = true) |-- workclass: string (nullable = true) |-- fnlwgt: float (nullable = true) |-- education: string (nullable = true) |-- education_num: float (nullable = true) |-- marital: string (nullable = true) |-- occupation: string (nullable = true) |-- relationship: string (nullable = true) |-- race: string (nullable = true) |-- sex: string (nullable = true) |-- capital_gain: float (nullable = true) |-- capital_loss: float (nullable = true) |-- hours_week: float (nullable = true) |-- native_country: string (nullable = true) |-- label: string (nullable = true) from pyspark.ml.feature import StringIndexer #stringIndexer = StringIndexer(inputCol="label", outputCol="newlabel") #model = stringIndexer.fit(df) #df = model.transform(df) df.printSchema()
اختيار الأعمدة
يمكنك تحديد وإظهار الصفوف مع تحديد وأسماء الميزات. أدناه، تم تحديد العمر وfnlwgt.
df.select('age','fnlwgt').show(5)
+---+------+ |age|fnlwgt| +---+------+ | 39| 77516| | 50| 83311| | 38|215646| | 53|234721| | 28|338409| +---+------+ only showing top 5 rows
العد حسب المجموعة
إذا كنت ترغب في حساب عدد مرات الظهور حسب المجموعة، يمكنك استخدام التسلسل التالي:
- مجموعة من()
- عدد()
معاً. في بايSpark في المثال أدناه، يمكنك حساب عدد الصفوف حسب مستوى التعليم.
df.groupBy("education").count().sort("count",ascending=True).show()
+------------+-----+ | education|count| +------------+-----+ | Preschool| 51| | 1st-4th| 168| | 5th-6th| 333| | Doctorate| 413| | 12th| 433| | 9th| 514| | Prof-school| 576| | 7th-8th| 646| | 10th| 933| | Assoc-acdm| 1067| | 11th| 1175| | Assoc-voc| 1382| | Masters| 1723| | Bachelors| 5355| |Some-college| 7291| | HS-grad|10501| +------------+-----+
وصف البيانات
للحصول على إحصائيات ملخصة للبيانات، يمكنك استخدام الوصف (). سوف يقوم بحساب :
- عد
- تعني
- الانحراف المعياري
- دقيقة
- ماكس
df.describe().show()
+-------+------------------+-----------+------------------+------------+-----------------+--------+----------------+------------+------------------+------+------------------+----------------+------------------+--------------+-----+ |summary| age| workclass| fnlwgt| education| education_num| marital| occupation|relationship| race| sex| capital_gain| capital_loss| hours_week|native_country|label| +-------+------------------+-----------+------------------+------------+-----------------+--------+----------------+------------+------------------+------+------------------+----------------+------------------+--------------+-----+ | count| 32561| 32561| 32561| 32561| 32561| 32561| 32561| 32561| 32561| 32561| 32561| 32561| 32561| 32561|32561| | mean| 38.58164675532078| null|189778.36651208502| null| 10.0806793403151| null| null| null| null| null|1077.6488437087312| 87.303829734959|40.437455852092995| null| null| | stddev|13.640432553581356| null|105549.97769702227| null|2.572720332067397| null| null| null| null| null| 7385.292084840354|402.960218649002|12.347428681731838| null| null| | min| 17| ?| 12285| 10th| 1|Divorced| ?| Husband|Amer-Indian-Eskimo|Female| 0| 0| 1| ?|<=50K| | max| 90|Without-pay| 1484705|Some-college| 16| Widowed|Transport-moving| Wife| White| Male| 99999| 4356| 99| Yugoslavia| >50K| +-------+------------------+-----------+------------------+------------+-----------------+--------+----------------+------------+------------------+------+------------------+----------------+------------------+--------------+-----+
إذا كنت تريد إحصائيات التلخيص لعمود واحد فقط، أضف اسم العمود داخل description()
df.describe('capital_gain').show()
+-------+------------------+ |summary| capital_gain| +-------+------------------+ | count| 32561| | mean|1077.6488437087312| | stddev| 7385.292084840354| | min| 0| | max| 99999| +-------+------------------+
حساب الجدولي
في بعض الأحيان، قد يكون من المثير للاهتمام رؤية الإحصائيات الوصفية بين عمودين متماثلين. على سبيل المثال، يمكنك حساب عدد الأشخاص الذين يقل دخلهم عن 50 ألف دولار أو يزيد حسب مستوى التعليم. تسمى هذه العملية الجدول المتقاطع.
df.crosstab('age', 'label').sort("age_label").show()
+---------+-----+----+ |age_label|<=50K|>50K| +---------+-----+----+ | 17| 395| 0| | 18| 550| 0| | 19| 710| 2| | 20| 753| 0| | 21| 717| 3| | 22| 752| 13| | 23| 865| 12| | 24| 767| 31| | 25| 788| 53| | 26| 722| 63| | 27| 754| 81| | 28| 748| 119| | 29| 679| 134| | 30| 690| 171| | 31| 705| 183| | 32| 639| 189| | 33| 684| 191| | 34| 643| 243| | 35| 659| 217| | 36| 635| 263| +---------+-----+----+ only showing top 20 rows
لا يمكنك أن ترى أن أي شخص لديه إيرادات تزيد عن 50 ألفًا عندما يكون صغيرًا.
عمود الإسقاط
هناك نوعان من واجهة برمجة التطبيقات البديهية لإسقاط الأعمدة:
- إسقاط (): إسقاط عمود
- dropna(): إسقاط NA
أدناه تقوم بإسقاط العمود education_num
df.drop('education_num').columns ['age', 'workclass', 'fnlwgt', 'education', 'marital', 'occupation', 'relationship', 'race', 'sex', 'capital_gain', 'capital_loss', 'hours_week', 'native_country', 'label']
تصفية البيانات
يمكنك استخدام عامل التصفية () لتطبيق الإحصائيات الوصفية في مجموعة فرعية من البيانات. على سبيل المثال، يمكنك حساب عدد الأشخاص الذين تزيد أعمارهم عن 40 عامًا
df.filter(df.age > 40).count()
13443
Descriptإحصائيات إيف حسب المجموعة
وأخيرًا، يمكنك تجميع البيانات حسب المجموعة وحساب العمليات الإحصائية مثل المتوسط.
df.groupby('marital').agg({'capital_gain': 'mean'}).show()
+--------------------+------------------+ | marital| avg(capital_gain)| +--------------------+------------------+ | Separated| 535.5687804878049| | Never-married|376.58831788823363| |Married-spouse-ab...| 653.9832535885167| | Divorced| 728.4148098131893| | Widowed| 571.0715005035247| | Married-AF-spouse| 432.6521739130435| | Married-civ-spouse|1764.8595085470085| +--------------------+------------------+
الخطوة 2) المعالجة المسبقة للبيانات
تعد معالجة البيانات خطوة حاسمة في التعلم الآلي. بعد إزالة البيانات المهملة، يمكنك الحصول على بعض الأفكار المهمة.
على سبيل المثال، أنت تعلم أن العمر ليس دالة خطية مع الدخل. عندما يكون الناس صغارًا، يكون دخلهم عادةً أقل من منتصف العمر. بعد التقاعد، تستخدم الأسرة مدخراتها، مما يعني انخفاض الدخل. لالتقاط هذا النمط، يمكنك إضافة مربع إلى ميزة العمر
أضف مربع العمر
لإضافة ميزة جديدة، يجب عليك:
- حدد العمود
- قم بتطبيق التحويل وإضافته إلى DataFrame
from pyspark.sql.functions import * # 1 Select the column age_square = df.select(col("age")**2) # 2 Apply the transformation and add it to the DataFrame df = df.withColumn("age_square", col("age")**2) df.printSchema() root |-- age: integer (nullable = true) |-- workclass: string (nullable = true) |-- fnlwgt: integer (nullable = true) |-- education: string (nullable = true) |-- education_num: integer (nullable = true) |-- marital: string (nullable = true) |-- occupation: string (nullable = true) |-- relationship: string (nullable = true) |-- race: string (nullable = true) |-- sex: string (nullable = true) |-- capital_gain: integer (nullable = true) |-- capital_loss: integer (nullable = true) |-- hours_week: integer (nullable = true) |-- native_country: string (nullable = true) |-- label: string (nullable = true) |-- age_square: double (nullable = true)
يمكنك أن ترى أنه تمت إضافة age_square بنجاح إلى إطار البيانات. يمكنك تغيير ترتيب المتغيرات باستخدام التحديد. أدناه، تقوم بإحضار age_square مباشرة بعد العمر.
COLUMNS = ['age', 'age_square', 'workclass', 'fnlwgt', 'education', 'education_num', 'marital', 'occupation', 'relationship', 'race', 'sex', 'capital_gain', 'capital_loss', 'hours_week', 'native_country', 'label'] df = df.select(COLUMNS) df.first()
Row(age=39, age_square=1521.0, workclass='State-gov', fnlwgt=77516, education='Bachelors', education_num=13, marital='Never-married', occupation='Adm-clerical', relationship='Not-in-family', race='White', sex='Male', capital_gain=2174, capital_loss=0, hours_week=40, native_country='United-States', label='<=50K')
استبعاد هولندا-هولندا
عندما تحتوي مجموعة داخل الميزة على ملاحظة واحدة فقط، فإنها لا تقدم أي معلومات إلى النموذج. على العكس من ذلك، يمكن أن يؤدي ذلك إلى حدوث خطأ أثناء التحقق من الصحة.
دعونا نتحقق من أصل الأسرة
df.filter(df.native_country == 'Holand-Netherlands').count() df.groupby('native_country').agg({'native_country': 'count'}).sort(asc("count(native_country)")).show()
+--------------------+---------------------+ | native_country|count(native_country)| +--------------------+---------------------+ | Holand-Netherlands| 1| | Scotland| 12| | Hungary| 13| | Honduras| 13| |Outlying-US(Guam-...| 14| | Yugoslavia| 16| | Thailand| 18| | Laos| 18| | Cambodia| 19| | Trinadad&Tobago| 19| | Hong| 20| | Ireland| 24| | Ecuador| 28| | Greece| 29| | France| 29| | Peru| 31| | Nicaragua| 34| | Portugal| 37| | Iran| 43| | Haiti| 44| +--------------------+---------------------+ only showing top 20 rows
تضم الميزة original_country أسرة واحدة فقط قادمة من هولندا. أنت تستبعده.
df_remove = df.filter(df.native_country != 'Holand-Netherlands')
الخطوة 3) بناء خط أنابيب معالجة البيانات
على غرار مكتبة scikit-learn، PySpark يحتوي على واجهة برمجة تطبيقات لخط الأنابيب.
يعد خط الأنابيب مفيدًا جدًا للحفاظ على بنية البيانات. تقوم بدفع البيانات إلى خط الأنابيب. داخل خط الأنابيب، تتم عمليات مختلفة، ويتم استخدام الناتج لتغذية الخوارزمية.
على سبيل المثال، أحد التحولات الشاملة في التعلم الآلي يتكون من تحويل سلسلة إلى برنامج تشفير واحد ساخن، أي عمود واحد بواسطة مجموعة. عادةً ما يكون أحد برامج التشفير الساخنة عبارة عن مصفوفة مليئة بالأصفار.
خطوات تحويل البيانات مشابهة جدًا لخطوات scikit-Learn. أنت بحاجه إلى:
- فهرسة السلسلة إلى رقمية
- قم بإنشاء برنامج تشفير سريع واحد
- تحويل البيانات
هناك واجهتان من واجهات برمجة التطبيقات (APIs) تقومان بهذه المهمة: StringIndexer وOneHotEncoder
- أولاً، عليك تحديد عمود السلسلة المراد فهرسته. inputCol هو اسم العمود في مجموعة البيانات. OutputCol هو الاسم الجديد المعطى للعمود المحول.
StringIndexer(inputCol="workclass", outputCol="workclass_encoded")
- احتواء البيانات وتحويلها
model = stringIndexer.fit(df)
`indexed = model.transform(df)``
- قم بإنشاء أعمدة الأخبار بناءً على المجموعة. على سبيل المثال، إذا كانت هناك 10 مجموعات في الميزة، فستحتوي المصفوفة الجديدة على 10 أعمدة، عمود واحد لكل مجموعة.
OneHotEncoder(dropLast=False, inputCol="workclassencoded", outputCol="workclassvec")
### Example encoder from pyspark.ml.feature import StringIndexer, OneHotEncoder, VectorAssembler stringIndexer = StringIndexer(inputCol="workclass", outputCol="workclass_encoded") model = stringIndexer.fit(df) indexed = model.transform(df) encoder = OneHotEncoder(dropLast=False, inputCol="workclass_encoded", outputCol="workclass_vec") encoded = encoder.transform(indexed) encoded.show(2)
+---+----------+----------------+------+---------+-------------+------------------+---------------+-------------+-----+----+------------+------------+----------+--------------+-----+-----------------+-------------+ |age|age_square| workclass|fnlwgt|education|education_num| marital| occupation| relationship| race| sex|capital_gain|capital_loss|hours_week|native_country|label|workclass_encoded|workclass_vec| +---+----------+----------------+------+---------+-------------+------------------+---------------+-------------+-----+----+------------+------------+----------+--------------+-----+-----------------+-------------+ | 39| 1521.0| State-gov| 77516|Bachelors| 13| Never-married| Adm-clerical|Not-in-family|White|Male| 2174| 0| 40| United-States|<=50K| 4.0|(9,[4],[1.0])| | 50| 2500.0|Self-emp-not-inc| 83311|Bachelors| 13|Married-civ-spouse|Exec-managerial| Husband|White|Male| 0| 0| 13| United-States|<=50K| 1.0|(9,[1],[1.0])| +---+----------+----------------+------+---------+-------------+------------------+---------------+-------------+-----+----+------------+------------+----------+--------------+-----+-----------------+-------------+ only showing top 2 rows
بناء خط الانابيب
ستقوم ببناء خط أنابيب لتحويل كافة الميزات الدقيقة وإضافتها إلى مجموعة البيانات النهائية. سيتضمن خط الأنابيب أربع عمليات، ولكن لا تتردد في إضافة أي عدد تريده من العمليات.
- تشفير البيانات الفئوية
- فهرسة ميزة التسمية
- إضافة متغير مستمر
- تجميع الخطوات.
يتم تخزين كل خطوة في قائمة تسمى المراحل. ستخبر هذه القائمة VectorAssembler بالعملية التي يجب إجراؤها داخل خط الأنابيب.
1. تشفير البيانات الفئوية
هذه الخطوة هي نفسها تمامًا كما في المثال أعلاه، باستثناء أنك تقوم بالتكرار على جميع السمات الفئوية.
from pyspark.ml import Pipeline from pyspark.ml.feature import OneHotEncoderEstimator CATE_FEATURES = ['workclass', 'education', 'marital', 'occupation', 'relationship', 'race', 'sex', 'native_country'] stages = [] # stages in our Pipeline for categoricalCol in CATE_FEATURES: stringIndexer = StringIndexer(inputCol=categoricalCol, outputCol=categoricalCol + "Index") encoder = OneHotEncoderEstimator(inputCols=[stringIndexer.getOutputCol()], outputCols=[categoricalCol + "classVec"]) stages += [stringIndexer, encoder]
ملاحظة حول واجهة برمجة التطبيقات: تم دمج OneHotEncoderEstimator مرة أخرى في OneHotEncoder في Spark 3.0. على Spark في الإصدار 3.x أو أحدث، قم باستيراد OneHotEncoder وقم بتمرير نفس وسيطات inputCols و outputCols؛ بقية الحلقة لم تتغير.
2. قم بفهرسة ميزة التسمية
Spark، مثل العديد من المكتبات الأخرى، لا تقبل قيم السلسلة للتسمية. يمكنك تحويل ميزة التسمية باستخدام StringIndexer وإضافتها إلى مراحل القائمة
# Convert label into label indices using the StringIndexer label_stringIdx = StringIndexer(inputCol="label", outputCol="newlabel") stages += [label_stringIdx]
3. إضافة متغير مستمر
تُعدّ قائمة الأعمدة (inputCols) في VectorAssembler قائمةً بالأعمدة. يمكنك إنشاء قائمة جديدة تحتوي على جميع الأعمدة الجديدة. يقوم الكود أدناه بتعبئة القائمة بالخصائص الفئوية المشفرة والخصائص المستمرة.
assemblerInputs = [c + "classVec" for c in CATE_FEATURES] + CONTI_FEATURES
4. قم بتجميع الخطوات.
وأخيرًا، قمت باجتياز كافة الخطوات الموجودة في VectorAssembler
assembler = VectorAssembler(inputCols=assemblerInputs, outputCol="features")stages += [assembler]
الآن بعد أن أصبحت جميع الخطوات جاهزة، يمكنك دفع البيانات إلى المسار.
# Create a Pipeline.
pipeline = Pipeline(stages=stages)
pipelineModel = pipeline.fit(df_remove)
model = pipelineModel.transform(df_remove)
إذا قمت بفحص مجموعة البيانات الجديدة، يمكنك أن ترى أنها تحتوي على جميع الميزات، المحولة وغير المحولة. أنت مهتم فقط بالعلامة الجديدة والميزات. تتضمن الميزات جميع الميزات المحولة والمتغيرات المستمرة.
model.take(1) [Row(age=39, age_square=1521.0, workclass='State-gov', fnlwgt=77516, education='Bachelors', education_num=13, marital='Never-married', occupation='Adm-clerical', relationship='Not-in-family', race='White', sex='Male', capital_gain=2174, capital_loss=0, hours_week=40, native_country='United-States', label='<=50K', workclassIndex=4.0, workclassclassVec=SparseVector(8, {4: 1.0}), educationIndex=2.0, educationclassVec=SparseVector(15, {2: 1.0}), maritalIndex=1.0, maritalclassVec=SparseVector(6, {1: 1.0}), occupationIndex=3.0, occupationclassVec=SparseVector(14, {3: 1.0}), relationshipIndex=1.0, relationshipclassVec=SparseVector(5, {1: 1.0}), raceIndex=0.0, raceclassVec=SparseVector(4, {0: 1.0}), sexIndex=0.0, sexclassVec=SparseVector(1, {0: 1.0}), native_countryIndex=0.0, native_countryclassVec=SparseVector(40, {0: 1.0}), newlabel=0.0, features=SparseVector(99, {4: 1.0, 10: 1.0, 24: 1.0, 32: 1.0, 44: 1.0, 48: 1.0, 52: 1.0, 53: 1.0, 93: 39.0, 94: 77516.0, 95: 2174.0, 96: 13.0, 98: 40.0}))]
الخطوة 4) بناء المصنف: لوجستي
لجعل الحساب أسرع، يمكنك تحويل النموذج إلى DataFrame.
تحتاج إلى تحديد التسمية الجديدة والميزات من النموذج باستخدام الخريطة.
from pyspark.ml.linalg import DenseVector input_data = model.rdd.map(lambda x: (x["newlabel"], DenseVector(x["features"])))
أنت جاهز لإنشاء بيانات القطار كإطار بيانات. يمكنك استخدام sqlContext
df_train = sqlContext.createDataFrame(input_data, ["label", "features"])
تحقق من الصف الثاني
df_train.show(2)
+-----+--------------------+ |label| features| +-----+--------------------+ | 0.0|[0.0,0.0,0.0,0.0,...| | 0.0|[0.0,1.0,0.0,0.0,...| +-----+--------------------+ only showing top 2 rows
قم بإنشاء مجموعة تدريب/اختبار
لقد قمت بتقسيم مجموعة البيانات بنسبة 80/20 باستخدام RandomSplit.
# Split the data into train and test sets
train_data, test_data = df_train.randomSplit([.8,.2],seed=1234)
دعونا نحسب عدد الأشخاص الذين لديهم دخل أقل/أعلى من 50 ألفًا في كل من مجموعة التدريب والاختبار
train_data.groupby('label').agg({'label': 'count'}).show()
+-----+------------+ |label|count(label)| +-----+------------+ | 0.0| 19698| | 1.0| 6263| +-----+------------+
test_data.groupby('label').agg({'label': 'count'}).show()
+-----+------------+ |label|count(label)| +-----+------------+ | 0.0| 5021| | 1.0| 1578| +-----+------------+
بناء التراجع اللوجستي
وأخيرًا وليس آخرًا، يمكنك بناء المصنف. بايثونSpark يحتوي على واجهة برمجة تطبيقات تسمى LogisticRegression لإجراء الانحدار اللوجستي.
يمكنك تهيئة lr من خلال الإشارة إلى عمود التسمية وأعمدة الميزات. قمت بتعيين 10 تكرارات كحد أقصى وإضافة معلمة تنظيم بقيمة 0.3. لاحظ أنه في القسم التالي، ستستخدم التحقق المتبادل مع شبكة المعلمات لضبط النموذج
# Import `LinearRegression` from pyspark.ml.classification import LogisticRegression # Initialize `lr` lr = LogisticRegression(labelCol="label", featuresCol="features", maxIter=10, regParam=0.3) # Fit the data to the model linearModel = lr.fit(train_data)
# يمكنك رؤية المعاملات من الانحدار
# Print the coefficients and intercept for logistic regression print("Coefficients: " + str(linearModel.coefficients)) print("Intercept: " + str(linearModel.intercept))
Coefficients: [-0.0678914665262,-0.153425526813,-0.0706009536407,-0.164057586562,-0.120655298528,0.162922330862,0.149176870438,-0.626836362611,-0.193483661541,-0.0782269980838,0.222667203836,0.399571096381,-0.0222024341804,-0.311925857859,-0.0434497788688,-0.306007744328,-0.41318209688,0.547937504247,-0.395837350854,-0.23166535958,0.618743906733,-0.344088614546,-0.385266881369,0.317324463006,-0.350518889186,-0.201335923138,-0.232878560088,-0.13349278865,-0.119760542498,0.17500602491,-0.0480968101118,0.288484253943,-0.116314616745,0.0524163478063,-0.300952624551,-0.22046421474,-0.16557996579,-0.114676231939,-0.311966431453,-0.344226119233,0.105530129507,0.152243047814,-0.292774545497,0.263628334433,-0.199951374076,-0.30329422583,-0.231087515178,0.418918551,-0.0565930184279,-0.177818073048,-0.0733236680663,-0.267972912252,0.168491215697,-0.12181255723,-0.385648075442,-0.202101794517,0.0469791640782,-0.00842850210625,-0.00373211448629,-0.259296141281,-0.309896554133,-0.168434409756,-0.11048086026,0.0280647963877,-0.204187030092,-0.414392623536,-0.252806580669,0.143366465705,-0.516359222663,-0.435627370849,-0.301949286524,0.0878249035894,-0.210951740965,-0.621417928742,-0.099445190784,-0.232671473401,-0.1077745606,-0.360429419703,-0.420362959052,-0.379729467809,-0.395186242741,0.0826401853838,-0.280251589972,0.187313505214,-0.20295228799,-0.431177064626,0.149759018379,-0.107114299614,-0.319314858424,0.0028450133235,-0.651220387649,-0.327918792207,-0.143659581445,0.00691075160413,8.38517628783e-08,2.18856717378e-05,0.0266701216268,0.000231075966823,0.00893832698698] Intercept: -1.9884177974805692
الخطوة 5) تدريب النموذج وتقييمه
لتوليد التنبؤ لمجموعة الاختبار الخاصة بك،
يمكنك استخدام الخط الخطي مع التحويل () في test_data
# Make predictions on test data using the transform() method.
predictions = linearModel.transform(test_data)
يمكنك طباعة العناصر في التنبؤات
predictions.printSchema() root |-- label: double (nullable = true) |-- features: vector (nullable = true) |-- rawPrediction: vector (nullable = true) |-- probability: vector (nullable = true) |-- prediction: double (nullable = false)
أنت مهتم بالتسمية والتنبؤ والاحتمال
selected = predictions.select("label", "prediction", "probability") selected.show(20)
+-----+----------+--------------------+ |label|prediction| probability| +-----+----------+--------------------+ | 0.0| 0.0|[0.91560704124179...| | 0.0| 0.0|[0.92812140213994...| | 0.0| 0.0|[0.92161406774159...| | 0.0| 0.0|[0.96222760777142...| | 0.0| 0.0|[0.66363283056957...| | 0.0| 0.0|[0.65571324475477...| | 0.0| 0.0|[0.73053376932829...| | 0.0| 1.0|[0.31265053873570...| | 0.0| 0.0|[0.80005907577390...| | 0.0| 0.0|[0.76482251301640...| | 0.0| 0.0|[0.84447301189069...| | 0.0| 0.0|[0.75691912026619...| | 0.0| 0.0|[0.60902504096722...| | 0.0| 0.0|[0.80799228385509...| | 0.0| 0.0|[0.87704364852567...| | 0.0| 0.0|[0.83817652582377...| | 0.0| 0.0|[0.79655423248500...| | 0.0| 0.0|[0.82712311232246...| | 0.0| 0.0|[0.81372823882016...| | 0.0| 0.0|[0.59687710752201...| +-----+----------+--------------------+ only showing top 20 rows
قيم النموذج
أنت بحاجة إلى إلقاء نظرة على مقياس الدقة لمعرفة مدى جودة (أو سوء) أداء النموذج. حاليًا، لا توجد واجهة برمجة التطبيقات (API) لحساب قياس الدقة Sparkالقيمة الافتراضية هي ROC، منحنى خصائص تشغيل المستقبل. وهي مقياس مختلف يأخذ في الاعتبار معدل النتائج الإيجابية الخاطئة.
قبل أن تنظر إلى ROC، دعنا نبني مقياس الدقة. أنت أكثر دراية بهذا المقياس. مقياس الدقة هو مجموع التنبؤ الصحيح على إجمالي عدد الملاحظات.
يمكنك إنشاء DataFrame باستخدام التسمية و"التنبؤ".
cm = predictions.select("label", "prediction")
يمكنك التحقق من عدد الفئة في التسمية والتنبؤ
cm.groupby('label').agg({'label': 'count'}).show()
+-----+------------+ |label|count(label)| +-----+------------+ | 0.0| 5021| | 1.0| 1578| +-----+------------+
cm.groupby('prediction').agg({'prediction': 'count'}).show()
+----------+-----------------+ |prediction|count(prediction)| +----------+-----------------+ | 0.0| 5982| | 1.0| 617| +----------+-----------------+
على سبيل المثال، في مجموعة الاختبار، هناك 1578 أسرة يزيد دخلها عن 50 ألفًا و5021 أدناه. ومع ذلك، توقع المصنف وجود 617 أسرة يزيد دخلها عن 50 ألفًا.
يمكنك حساب الدقة عن طريق حساب العدد عندما يتم تصنيف التسمية بشكل صحيح على إجمالي عدد الصفوف.
cm.filter(cm.label == cm.prediction).count() / cm.count()
0.8237611759357478
يمكنك تجميع كل شيء معًا وكتابة دالة لحساب الدقة.
def accuracy_m(model): predictions = model.transform(test_data) cm = predictions.select("label", "prediction") acc = cm.filter(cm.label == cm.prediction).count() / cm.count() print("Model accuracy: %.3f%%" % (acc * 100)) accuracy_m(model = linearModel) Model accuracy: 82.376%
مقاييس ROC
تتضمن الوحدة النمطية BinaryClassificationEvaluator مقاييس ROC. المستقبل Operaيعد المنحنى المميز أداة شائعة أخرى تستخدم في التصنيف الثنائي. وهو مشابه جدًا لمنحنى الدقة/الاستدعاء، ولكن بدلاً من رسم الدقة مقابل الاستدعاء، يُظهر منحنى ROC المعدل الإيجابي الحقيقي (أي الاستدعاء) مقابل المعدل الإيجابي الخاطئ. المعدل الإيجابي الكاذب هو نسبة الحالات السلبية التي تم تصنيفها بشكل غير صحيح على أنها إيجابية. وهو يساوي واحدًا ناقص المعدل السلبي الحقيقي. ويسمى المعدل السلبي الحقيقي أيضًا بالخصوصية. ومن ثم فإن منحنى ROC يرسم الحساسية (الاستدعاء) مقابل 1 – النوعية
### Use ROC from pyspark.ml.evaluation import BinaryClassificationEvaluator # Evaluate model evaluator = BinaryClassificationEvaluator(rawPredictionCol="rawPrediction") print(evaluator.evaluate(predictions)) print(evaluator.getMetricName())
0.8940481662695192 منطقة تحت ROC
print(evaluator.evaluate(predictions))
0.8940481662695192
الخطوة 6) ضبط المعلمة الفائقة
وأخيرًا وليس آخرًا، يمكنك ضبط المعلمات الفائقة. على غرار مكتبة scikit-learn، يمكنك إنشاء شبكة معلمات، وإضافة المعلمات التي ترغب في ضبطها.
لتقليل وقت الحساب، يمكنك فقط ضبط معلمة التنظيم بقيمتين فقط.
from pyspark.ml.tuning import ParamGridBuilder, CrossValidator # Create ParamGrid for Cross Validation paramGrid = (ParamGridBuilder() .addGrid(lr.regParam, [0.01, 0.5]) .build())
وأخيرًا، يتم تقييم النموذج باستخدام طريقة التحقق المتقاطع بخمسة طيات. ويستغرق التدريب حوالي 16 دقيقة.
from time import * start_time = time() # Create 5-fold CrossValidator cv = CrossValidator(estimator=lr, estimatorParamMaps=paramGrid, evaluator=evaluator, numFolds=5) # Run cross validations cvModel = cv.fit(train_data) # likely take a fair amount of time end_time = time() elapsed_time = end_time - start_time print("Time to train model: %.3f seconds" % elapsed_time)
زمن تدريب النموذج: 978.807 ثانية
أفضل معلمة تنظيمية هي 0.01 بدقة 85.316 بالمائة.
accuracy_m(model = cvModel) Model accuracy: 85.316%
يمكنك الخروجtract المعلمة الموصى بها عن طريق ربط cvModel.bestModel مع extractParamMap()
bestModel = cvModel.bestModel bestModel.extractParamMap()
{Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='aggregationDepth', doc='suggested depth for treeAggregate (>= 2)'): 2,
Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='elasticNetParam', doc='the ElasticNet mixing parameter, in range [0, 1]. For alpha = 0, the penalty is an L2 penalty. For alpha = 1, it is an L1 penalty'): 0.0,
Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='family', doc='The name of family which is a description of the label distribution to be used in the model. Supported options: auto, binomial, multinomial.'): 'auto',
Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='featuresCol', doc='features column name'): 'features',
Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='fitIntercept', doc='whether to fit an intercept term'): True,
Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='labelCol', doc='label column name'): 'label',
Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='maxIter', doc='maximum number of iterations (>= 0)'): 10,
Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='predictionCol', doc='prediction column name'): 'prediction',
Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='probabilityCol', doc='Column name for predicted class conditional probabilities. Note: Not all models output well-calibrated probability estimates! These probabilities should be treated as confidences, not precise probabilities'): 'probability',
Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='rawPredictionCol', doc='raw prediction (a.k.a. confidence) column name'): 'rawPrediction',
Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='regParam', doc='regularization parameter (>= 0)'): 0.01,
Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='standardization', doc='whether to standardize the training features before fitting the model'): True,
Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='threshold', doc='threshold in binary classification prediction, in range [0, 1]'): 0.5,
Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='tol', doc='the convergence tolerance for iterative algorithms (>= 0)'): 1e-06}


