بدأ مشروع Geni بواسطة

فريق بيانات Zero One Group في منتصف عام 2020 ويرجع ذلك جزئيًا إلى إحباطاتنا مع أداء الباندا غير المتوقع. كان من الممكن أن نسير على طريقة PySpark ، ولكن منذ أن بدأ باقي الفريق في استخدام Clojure ، أردنا أن يكون لدينا صدع في استخدام Clojure لوظائف البيانات لدينا.

لا تحاول القطعة التالية تقديم نتائج قياس أداء عادلة ودقيقة. بدلاً من ذلك ، هو توضيح عمليات التسريع النموذجية التي كان فريقنا جاهزًا لفهمها ولحالات الاستخدام المحددة الخاصة بنا. لذلك فإن النتائج المعروضة هنا يجب أن تؤخذ بحذر.

بيانات التجزئة الوهمية

في منتصف عام 2020 ، عملنا على مشروع تقسيم العملاء لأحد عمالقة التجزئة في إندونيسيا . كنا نعمل مع أكثر من 20 مليون معاملة و 4 ملايين عميل. نحن نحاكي بيانات وهمية تمثيلية بشكل معقول باستخدام Geni. جوهر المحاكاة هو كما يلي:

( -> ( معرّف المعاملة Col

) :معرف العضو ( ز / int ( ز / ريكس 5 e-6)) :كمية ( ز / int ( ز / inc ( g / rexp ))) :السعر ( ز / الأسرى 2 ( ز / عشوائي إنت 16 20 )) : معرف النمط ( ز / إنت ( ز / rexp 1 ه -2)) : معرف العلامة التجارية ( ز / إنت ( g / rexp 1 ه -2)) :عام 2019 : الشهر يوم الشهر (

ز / عشوائي int 1

( المؤتمر الوطني العراقي ( ماكس أيام شهر)))}) ( ز / مع العمود :تاريخ ( ز / حتى الآن التاريخ كول)))

هنا .

مجموعة- بواسطة + التجميع العملية

تحتوي البيانات الوهمية 24 مليون معاملة بالضبط وحوالي مليون عميل. المهمة بسيطة. نود أن نعرف لكل عميل:

كم أنفقوا ؛

  • متوسط ​​حجم السلة ؛
  • متوسط ​​إنفاقهم لكل معاملة ؛

  • عدد المعاملات ؛
  • عدد الزيارات ؛

    عدد العلامات التجارية المختلفة التي قاموا بشرائها ؛ و

  • عدد الأنماط المختلفة التي قاموا بشرائها.
  • ) ( ز / أغ {:إجمالي الإنفاق ( جم / سوم :مبيعات ) : متوسط ​​حجم السلة ( ز / يعني : المبيعات ) : متوسط ​​السعر ( ز / يعني :السعر) : n- المعاملات ( غ / العد ) : n- الزيارات ( ز / عدد مميز :تاريخ) : n- العلامات التجارية ( ز / عدد مميز : معرف العلامة التجارية ) : أنماط n ( ز / عدد مميز : style-id )}) ( ز / أكتب باركيه! ” الهدف / الجيني -matrix.parquet ” {:الوضع الكتابة فوق })

    تستخدم محاولتنا الأولى لـ Pandas دالة تجميع مخصصة:

     ) ( المعاملات  .مجموعة من ('معرف العضو') .تطبيق ( لامدا 

    مجمعة : PD

    . سلسلة({ ‘إجمالي الإنفاق : مجمعة .مجموع ()، “متوسط ​​حجم السلة” :

    مجمعة .يعني ()، “متوسط ​​السعر”

    : مجمعة [‘price’]. يعني () ، “n-المعاملات” : لين ( مجمعة ) ، “n- الزيارات” : لين ( مجمعة [‘date’]. فريد()) ، “n-brand”

    : لين

    ( مجمعة [‘brand-id’]. ش أنيق ()) ، “n-styles” : لين ( مجمعة [‘style-id’]. فريد())، })) . إلى باركيه ( ‘target / pandas-matrix.parquet’ ))

    هنا.

    R: dplyr

      إطار البيانات 

    ٪ > ٪ متحور ( المبيعات = السعر الكمية > ٪ group_by ( `معرف العضو` )٪ > ٪ تلخيص ( total_spend = مجموع (مبيعات) ، avg_basket_size =

    يعني ( مبيعات ) ، متوسط ​​السعر = يعني ( السعر)، n_transactions = ن () ، n_visits = n_ مميزة ( التاريخ )، n_brands = n_ مميز ( `معرف العلامة التجارية` ) ، n_styles = n_ مميز ( `معرف النمط` ))٪ > ٪ Write_parquet ( باركيه نهائي “ )

    يمكن العثور على النص الكامل

    هنا

    . R: جدول البيانات

     

    إطار البيانات [, sales := quantity * price] نتيجة =

    إطار البيانات [, .(total_spend = sum(sales), avg_basket_size = mean(sales), avg_price = mean(price), n_transactions = .N, n_visits = uniqueN(date), n_brands = uniqueN(`brand-id`), n_styles = uniqueN(`style-id`)), by = `member-id`] write_parquet ( النتيجة ، datatable.parquet “ )

    يمكن العثور على النص الكامل هنا.

    جوليا: DataFrames

     مدافع  . 

    مبيعات = df . السعر .* df . كمية gdf =

    جروب باي

    (مدافع ، :معرف العضو) ملخص =

      دمج  (gdf، : المبيعات  =>  مجموع 

    => : إجمالي الإنفاق، : مبيعات => يعني => : avg_basket_size ، :السعر

    => يعني => : متوسط ​​السعر ، الآن => : n_transactions ، :تاريخ => نونيك => : n_visits ، : brand_id => نونيك => : n_brands ، : style_id => نونيك => : n_styles ) ملخص |> حفظ( جوليا.فيذر ” )

    ال يمكن العثور على النص الكامل هنا.

    كلوجر: tech.ml.dataset لدينا ثلاثة متغيرات من TMD ، وكل واحد يتم تشغيله باستخدام نفس خيارات JVM مثل Geni. يستخدم الخيار الأول في Scicloj غطاء طاولة. وجدنا مفرش المائدة dplyr

    – مثل واجهة برمجة التطبيقات لتكون الأكثر وضوحًا وتشبه Geni الأصلي:

     (

    -> إطار البيانات ( api / add-or-replace-عمود

    مبيعات # ( dfn / (٪ السعر ) (٪ كمية

     ))) (

    api / group-by “معرف العضو

     ) (

    api / مجمّع {:مجموع- أنفق #( dfn / sum (٪ مبيعات ) : متوسط ​​حجم السلة #(د fn / يعني (٪

     "

    مبيعات)) : متوسط ​​السعر # ( dfn / يعني (٪ السعر ) : n- المعاملات api / عدد الصفوف : n- الزيارات # ( عدد (خامد ( ٪

    تاريخ))) : n- العلامات التجارية # ( عدد (خامد

    معرف العلامة التجارية “

    )) : أنماط n # ( عدد (خامد (٪ ” معرّف النمط )))} {:موازى؟ صحيح}) ( api / write-nippy! ” target / dataset-matrix.nippy.gz )

    . تصرخ ل توماس سوليج

    لـ تصحيح الأداء ولمساعدتنا في تحسين الكود!

    بعد التحدث إلى المؤلف الرئيسي لـ TMD ، كريس نورنبيرجر

    ، اكتشفنا أنه يمكن تحسين رمز مفرش المائدة بشكل أكبر. تشمل الاختناقات المحتملة:

    مع بعض المساعدة من كريس ، تمكنا من الحصول على الذي يحل المشكلة 1. كتب كريس

    البديل الثالث لـ TMD

    نفسه ! وأضاف دعمًا لـ Arrow وبعض الرموز المخصصة لمزيد من التحسين. بالطبع ، هو المتغير الأكثر أداءً من TMD!

    لاحظ ذلك ، في هذه المرحلة ، فإن مقارنات TMD ليست 100 ٪ من التفاح إلى التفاح ، لأن متغيرات TMD لها تنسيقات وأقسام بيانات مختلفة. ومع ذلك ، فإنه لا يزال يحل المشكلة الأصلية ، لذلك ما زلنا ندرج النتائج المعيارية أدناه!

    النتائج

    تم الحصول على النتائج التالية من جهاز مزود بـ 12 نواة من Intel (R) Core (TM) i7-5930K CPU @ 3.50 جيجاهرتز ، 3 × 8 جيجابايت من ذاكرة الوصول العشوائي DDR4 من Corsair و 512 جيجابايت من وحدة تحكم Samsung Electronics NVMe SSD SM981 / PM981. يوضح الجدول أدناه عدد الثواني التي استغرقتها لإكمال عملية تجميع تلو الأخرى مع واحد على اثني عشر (N=2،000،000) من البيانات والبيانات الكاملة (N=24،000،000) ، لذا فإن الأقل هو الأفضل:

    لغة مكتبة

    N=2،000،000 (ثانية) ن=24000000 (ثانية)

    بايثون
    الباندا (مع وظيفة agg المخصصة) 587 1،132

    R
    dplyr

    461

     992     جوليا 
    DataFrames (مع باركيه) 87 868 كلوجير غطاء طاولة 48 151 151

    R جدول البيانات 28
    143
    كلوجور tech.ml. مجموعة البيانات (محسّنة)

    18
    133 جوليا
    DataFrames (مع Feather) 16 41

    كلوجير
    tech.ml.dataset (محسَّن بواسطة Chris)
    9
    36 كلوجر
    جيني 8 39 بايثون الباندا (مع وظائف agg المضمنة) 3
    42

    بفضل Spark ، أصبح Geni سريعًا خارج منطقة الجزاء مع الحد الأدنى من التعديلات!

       ٪٪ item_read_more_button ٪٪

    ترك الرد

    من فضلك ادخل تعليقك
    من فضلك ادخل اسمك هنا