Lemmatize بشكل أسرع (PyMorphy2 و PyMystem3 وبعض السحر)

أعمل كمبرمج ، بما في ذلك التعلم الآلي فيما يتعلق بتحليل النص. عند معالجة لغة طبيعية ، يلزم التحضير الأولي للوثائق ، وإحدى الطرق هي lemmat - جلب جميع كلمات النص إلى أشكالها العادية ، مع مراعاة السياق.

في الآونة الأخيرة ، واجهنا مشكلة تكاليف الوقت الكبيرة لهذه العملية. في مهمة محددة ، كان هناك أكثر من 100000 مستند ، كان متوسط ​​طولها حوالي 1000 حرف ، وكان من الضروري تنفيذ المعالجة على جهاز كمبيوتر محلي عادي ، وليس على خادمنا للحسابات. لم نتمكن من العثور على حل على الإنترنت ، لكننا وجدناه بأنفسنا ، وأود مشاركته - لعرض تحليل مقارن لمكتبتي lemmatization الأكثر شيوعًا في هذه المقالة.



Pymorphy2


يعد PyMorphy2 أحد أشهرها - وهو موجود في كل حل تقريبًا يمكن العثور عليه على الشبكة. استخدمنا هذه المكتبة أيضًا ، وأظهرت نفسها بشكل مثالي ، حتى طُلب منها إجراء عملية لمعة لقاعدة البيانات بأكملها (كما كتبت أعلاه ، فهذه أكثر من 100 ألف وثيقة صغيرة). من أجل تحليل مثل هذا الحجم من المستندات ، سيستغرق PyMorphy2 حوالي 10 ساعات ، في حين أن تحميل المعالج طوال هذا الوقت سيكون في المتوسط ​​حوالي 30٪ (Intel Core i7 7740X).

Pymystem3


بحثًا عن حل آخر ، قمنا بتحليل المكتبة من Yandex PyMystem3 ، ولكن النتيجة كانت أسوأ مرتين تقريبًا (في الوقت المناسب) من PyMorphy2: ستستغرق معالجة 100 ألف مستند 16 ساعة.

بعض السحر


بدا غريبا بالنسبة لنا أن الحمل على المعالج كان صفر تقريبا. كان من الغريب أيضًا أنه من أجل الحصول على النتيجة من نص واحد ، حتى النص الكبير (3-4 آلاف حرف) ، استغرق PyMystem3 حوالي ثانية واحدة. لذلك ، قررنا الجمع بين النصوص عن طريق إضافة نوع من الفاصل بينهما ، والذي يمكننا من خلاله إعادة هيكل قائمة المستندات الخاصة بنا وإعطائها لمحات.

كود حل بايثون:

def checkExecTimeMystemOneText(texts):
    lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)]
    txtpart = lol(texts, 1000)
    res = []
    for txtp in txtpart:
        alltexts = ' '.join([txt + ' br ' for txt in txtp])

        words = mystem.lemmatize(alltexts)
        doc = []
        for txt in words:
            if txt != '\n' and txt.strip() != '':
                if txt == 'br':
                    res.append(doc)
                    doc = []
                else:
                    doc.append(txt)

أخذنا 1000 وثيقة لكل اتحاد ، وكان الفاصل بينهما "br" (تجدر الإشارة إلى أن النصوص باللغة الروسية ، والأبجدية اللاتينية والأحرف الخاصة ، التي أزلناها سابقًا). أدى هذا القرار إلى تسريع اللميتة بشكل كبير: في المتوسط ​​، اتضح حوالي 25 دقيقة لجميع 100 ألف مستند ، وكان حمل المعالج 20-40 ٪. صحيح أن هذا الحل يحمّل ذاكرة الوصول العشوائي أكثر: في المتوسط ​​، يبلغ حجمه حوالي 3-7 غيغابايت ، ولكن هذه نتيجة جيدة. إذا لم تكن هناك ذاكرة كافية ، فيمكنك تغيير عدد المستندات المراد دمجها ، على الرغم من أن هذا سيؤدي إلى إبطاء المعالجة ، فسيظل أسرع بكثير من نص واحد في كل مرة. أيضًا ، إذا سمحت كمية الذاكرة ، يمكنك زيادة هذه القيمة والحصول على النتيجة بشكل أسرع.

يوضح الجدول مقارنة بين المكتبات أثناء المعالجة على جهاز كمبيوتر محلي (Intel Core i7 7740X ، 32 جيجابايت من ذاكرة الوصول العشوائي):
طريقةزمنذاكرة الوصول العشوائي (ميجابايت)نسبه مئويه
Pymorphy2~ 9.5 ساعة500 - 60025 - 30٪
PyMystem3 بجملة واحدة~ 16 ساعة500 - 7000 - 1٪
PyMystem3 مع 1000 عرض26 دقيقة2000 - 700025 - 40٪

من المثير للاهتمام معرفة آراء المتخصصين الآخرين. ربما وجد شخص ما طريقة أكثر فاعلية من حيث الوقت في مضايقة النصوص القصيرة؟

ميخائيل كاباكوف ، كبير مهندسي البرمجيات ،
آنا ميخائيلوفا ، رئيس
مناجم البيانات ، اتحاد الدستور الغذائي

All Articles