ربما ، في كل مدينة في بيلاروسيا حيث توجد عربات ترولي ، توجد مجموعات VK أو دردشات على Telegram يتعقب فيها الأشخاص موقع وحدات التحكم. يتم ذلك بشكل أساسي حتى لا تدفع مقابل السفر والسفر مجانًا ، على الرغم من أن وصف المجموعات دائمًا ما يحتوي على حاشية "الدفع مقابل السفر".
في VC ، يبدو عادةً كما يلي:

تعليق نموذجي يشبه هذا:

الهيكل بسيط للغاية. في التعليق ، توجد أسماء للإيقاف حيث تم ملاحظة وحدات التحكم حاليًا ، وهناك أيضًا الاتجاه الذي يقفون فيه:

ونتيجة لذلك ، فإن التعليق هو كائن ذو توقف ووقت وتاريخ ، بالإضافة إلى معرف فريد يمكننا من خلاله التعرف عليه. باستخدام هذا ، يمكنك حساب الموقع الأكثر احتمالًا حيث توجد وحدات التحكم الآن.
تدريب
تحتاج أولاً إلى تحديد الجمهور المستهدف ، الذي سنقوم من خلاله بتحليل البيانات. يجب أن يكون للمجموعة نشاط كبير في التعليقات ، وإلا فإننا نجازف بالحصول على القليل جدًا من البيانات
في حالتي ، هذه هي مجموعة "Control Gomel".
سنقوم بتحليل التعليقات باستخدام واجهة VKontakte API الرسمية لبيثون
نحن نقوم بالمصادقة باستخدام مفتاح وصول المستخدم ، حيث قد يتم إغلاق بعض المجموعات ، ولا يمكن الوصول إلى تعليقاتهم إلا إذا تم قبولك في المجموعة.
بعد ذلك ، يمكنك البدء في استخراج التعليقات:
تلقي التعليقات
بادئ ذي بدء ، نحصل على آخر منشور متاح في المجموعة لسحب التعليقات من خلال vk.wall.getComments ، وتهيئة DataFrame ، حيث سنقوم بحفظ البيانات.
يحتوي كل منشور للتعليق على نقش "أتمنى لك يومًا سعيدًا ، وادفع الأجرة ولا تقع تحت السيطرة" ، لذا قم بتنزيل التعليقات ، والتحقق من محتويات المنشور والحصول على مجموعة من التعليقات التي يمكنك من خلالها أخذ البيانات.
أخذت تعليقات من المشاركات على مدار الثلاثة أشهر الماضية ، بالنظر إلى أن هناك منشورًا واحدًا يتم نشره يوميًا (الآن في نهاية نوفمبر ، وتبدأ السنة الدراسية في سبتمبر ، وعلى الأرجح أن يأخذ المتحكمون ذلك في الاعتبار ويغيرون أماكنهم العادية). من حيث المبدأ ، يمكن أخذ علامات أخرى في الاعتبار ، مثل ، على سبيل المثال ، الوقت من السنة.
بعض التعليقات مسدودة برسائل مثل "هل يوجد أحد على باريكين؟" إذا نظرت إلى هذه التعليقات (غير الضرورية) ، يمكنك تسليط الضوء على بعض العلامات:
- يحتوي النص على الكلمات "النظيفة" ، "اليسار" ، "لا أحد" وما شابه
- الكلمات "قل لي" ، "من" ، "ماذا" ، "كيف"
- الرموز ، مثل الرموز ، على سبيل المثال
بعد ذلك ، نتصفح مجموعة من التعليقات ونستخرج منها معرفًا فريدًا ونصًا ووقتًا وتاريخًا ويومًا من الأسبوع ، نضعها في DataFrame الذي تم إنشاؤه بالفعل.
تلقي التعليقاتimport re import time import pandas as pd import lp import vk_api import check_correctness def auth(): vk_session = vk_api.VkApi(lp.login, lp.password) vk_session.auth() vk = vk_session.get_api() return vk def getDataFromComments(vk, groupID):
وبالتالي ، تلقينا DataFrame مع نص التعليقات ومعرفهم ويوم الأسبوع والساعة والدقيقة التي كُتب فيها التعليق. نحتاج فقط إلى يوم الأسبوع وساعة الكتابة والنص. يبدو شيء مثل هذا:

تطهير البيانات
الآن نحن بحاجة لمسح البيانات. من الضروري إزالة الاتجاه من التعليق من أجل تقليل الأخطاء عند البحث عن مسافة Levenshtein. نجد التعبيرات "إلى الجانب" ، و "اذهب" ، و "كيف" ، و "قريب" ، حيث يتم اتباعها عادةً باسم المحطة الثانية ، ونحذفها مع ما يأتي بعدها ، وكذلك نستبدل بعض أسماء المصطلحات من المحطات بالآتي .
مسح البيانات from fuzzywuzzy import process def clear_commentary(text): """ - """ index = 0 splitted = text.split(" ") for i, s in enumerate(splitted): if len(splitted) == 1: return np.NaN if ((("" in s) or ("" in s) or ( "" in s) or ( "" in s)) and s is not ""): index = i if index is not 0 and index < len(splitted) - 2: for i in range(1, 4): splitted.remove(splitted[index]) string = " ".join(splitted) text = (string.lower()) elif index is not 0: splitted = splitted[:index] string = " ".join(splitted) text = string.lower() else: text = " ".join(splitted).lower() return text def clean_data(data): data.dropna(inplace=True) data["text"] = data["text"].map(lambda s: clear_commentary(s)) data.dropna(inplace=True) print("cleaned") return data
تحويل باستخدام المسافة Levenshtein
ننتقل مباشرة إلى مسافة ليفينشان. القليل من المساعدة: مسافة Levenshtein - الحد الأدنى لعدد العمليات لإدخال حرف واحد ، وحذف حرف واحد واستبدال حرف واحد بآخر ، ضروري لتحويل سطر واحد إلى آخر.
سوف نجدها باستخدام مكتبة
fuzzywuzzy . انها تساعدك بسرعة وسهولة حساب المسافة Levenshtein. لتسريع العمل ، يوصي مؤلفو المكتبة أيضًا بتثبيت مكتبة بيثون ليفينشتاين.
من أجل الحصول على نقاط توقف من التعليقات ، نحتاج إلى قائمة من المحطات. تم تقديمه لي من قبل مطور تطبيق GoTrans ، ألكسندر كوزلوف.
يجب توسيع القائمة ، مع إضافة بعض التوقفات التي لم تكن موجودة ، وتغيير جزء من الأسماء بحيث تكون في موقع أفضل.
توقفتوقف = ["سوبر ماركت" ، "مرج" ، "ريميبتخنيكا" ، "لينينغراد" ، "ياروسلافل" ، "بوليسكايا" ،
"ياروسلافل" ، "تيموفينكو" ، "8 مارس" ،
"بيت التجارة Rechitsky" ، "شارع Rechitsky" ، "السيرك" ، "متجر كبير" ، "Chongarskaya" ،
"chongarka" ، "ggu" ، "skorina" ، "الجامعة" ، "الأجهزة" ، "1000 الأشياء الصغيرة" ، "maya" ، "station" ،
"حديقة الخريجين" ، "التجارة والاقتصادية" ، "الذكرى" ، "المقاطعة الصغيرة 18" ، "المطار" ، "قدوم" ،
"gomelgeodezcentr" ، "Crystal" ، "بحيرة lyubenskoye" ، "سوق davydovsky" ، "davydovka" ،
"نهر sozh" ، "gomeldrev" ،
"Sevruki" ، "gmu رقم 1" ، "إلخ Rechitsky" ، "الزي" ، "مستشفى الأمراض المعدية" ، "معسكر النورس" ،
فولوتوفا ، كورال ، غوميلتورغماش ، غوميلبروكت ، فنشغوملستروي ، صحيفة ،
"كالينيكوفا" ، "إريمينو" ، "تقطير" ، "أتمتة صناعية خاصة" ، "المدرسة الثانية" ، "باريكينا" ،
"وحدات الآلة" ، "الشباب" ، "هيئة الصب" ، "الكيميائيون" ، "golovatsky" ، "budenny" ،
"spu67" ، "35" ، "gagarin" ، و 50 عامًا إلى مصنع Gomselmash "،" التل "،" مصنع الراديو "،
"الجدة" ، "الأعمال الزجاجية" ، "الكستناء" ، "تشغيل المحركات" ، "رواد الفضاء" ،
"rtsrm الأولي" ، "bykhovskaya" ، "معهد وزارة حالات الطوارئ" ، "dk gomselmash" ، "store" ، "rechitsky"
"Sevruks" ، "Osovtsy" ، "سائح" ، "مصنع لحوم" ، "Holy Trinity" ، "مدينة طبية" ، "أكتوبر" ،
"مستودع الزيت" ، "gomelloblavtotrans" ، "milkavita" ، "bakunin" ، "zip" ، "oma" ، "الراتنج" ،
"سوق البناء ksk" ، "بناء الطرق" ، "الحقل" ، "kamenetskaya" ، "البلشفية" ، "jakubovka" ،
"Borodina" ، "هايبرو هايبر ماركت" ، "الأبطال السريون" ، "9 مايو" ، "الكستناء" ، "الأطراف الصناعية" ،
"محطة iput" ، "شيوعية دولية" ، "كلية تربوية موسيقية" ، "شركة زراعية" ، "طريق الالتفاف" ، "النصر" ،
"الغربي" ، "اللؤلؤ" ، "فلاديمير" ، "جاف" ، "مستوصف" ، "إيفانوفا" ،
"بناء الآلات" ، "البتولاين" ، "60 عامًا" ، "مهندس كهرباء" ، "سنتروليت" ،
"عيادة الأورام" ، "مجموعة الرماية" ، "golovintsy" ، "المرجان" ، "الجنوبية" ، "الربيع" ،
Efremova ، الحدود ، Belgut ، جوميلستروي ، بوريسينكو ، قصر ألعاب القوى ،
"Michurinsky" ، "الطاقة الشمسية" ، "gastello" ، "العسكرية" ، "مركز السيارات" ، "السباكة" ، "Uza" ،
"كلية الطب" ، "رياض الأطفال 11" ، "البلشفية" ، "الجراء" ، "دافيدوفسكي" ، "المحيط" ، "التقدم" ،
"Dobrushskaya" ، "الأبيض" ، "GSK" ، "davydovka" ، "المعدات الكهربائية" ، "الصداقة" ،
"70 سنة" ، "إصلاح سيارة" ، "تل سويدي" ، "دائرة" ، "قناة مياه" ، "آلة غوميل" ،
Volotova، Pioneer، RCM، Khimtorg، 2nd Meadow Lane، Bochkina، حمامات،
"عيادة الأورام" ، "المربع" ، "لينين" ، "المدرسة الأولى" ، "المتجر الجنوبي" ،
"gomelagrotrans" ، "millers" ، "lyubensky" ، "مكتب تجنيد عسكري" ، "مستشفى" ، "Uza" ، "rtsrm" ،
'lysyukovyh' ، 'متجر iput' ، 'raton' ، 'محطة وقود' ، 'randovsky' ، 'مزرعة' ، 'كستناء' ، 'ropovsky' ،
"رومانوفيتشي" ، "إيليتش" ، "التجديف" ، "مؤسسة البناء" ، "المعدية" ،
"مصنع الدهون" ، "خدمة السيارات" ، "الخدمات الزراعية" ، "لزجة" ، "نيكولسكايا" ،
"الحصادات ذاتية الدفع" ، "البنائين" ، "مواد البناء" ، "آلات الإصلاح" ، "الإدارة" ،
"أكتوبر" ، "حكاية خرافية الغابات" ، "تاتيانا" ، "بوريس تساريكوف" ، "زاركوفسكي" ، "زايتسيفا" ،
"النقل" ، "Karpovich" ، "محطة بناء المنازل" ، "النقل الكهربائي في المدينة" ، "zlin" ،
"ملعب gomselmash" ، "ap 6" ، "محرك هيدروليكي" ، "مستودع قاطرة" ، "osovtsy سوق السيارات" ،
"حياة جديدة" ، "جوكوفا" ، "وحدة عسكرية" ، "مدرسة ثالثة" ، "غابة" ، "منارة حمراء" ،
"الإقليمية" ، "دافيدوفسكايا" ، "كاربيشيفا" ، "قمر العالم" ، "الشباب" ، "قاطرة الاستاد" ،
"الطاقة الشمسية" ، "لاديسيرفيسي" ، "21 رر" ، "آريسا" ، "الدوليون" ، "كوساريفا" ،
"بوغدانوفا" ، "غوميل للحديد والخرسانة" ، "20 أ" ، "ريتشيتسكي" ، "معدات طبية" ، "جورايفا" ،
"كلية الحرف الفنية" ، "الجليد" ، "مهرجان دبي للتسوق" ، "مركز التسوق" ،
"كويبيشيفسكي" ، "مهرجان" ، "مرآب كووب 27" ، "هندسة زلزالية" ، "ميلشا" ، "مستشفى أنبوب" ،
"ptu179" ، "المنتجات الكيماوية" ، "إدارة الإطفاء" ، "المستشفى" ، "مستودع الحافلات" ،
"مجمع الصحف" ، "النصر" ، "klenkovsky" ، "الماس" ، "إصلاح المحرك" ، "mkr 19"]
باستخدام .map و fuzzywuzzy.process.extractOne ، نجد المحطة مع الحد الأدنى لمسافة Levenshtein في القائمة ، وبعد ذلك نستبدل نص التعليق باسم المحطة ، مما يسمح لنا بالحصول على مجموعة بيانات بأسماء المحطات.
تبدو مجموعة البيانات الناتجة مثل هذا:

التعليقات تتحول إلى توقف def get_category_from_comment(text): """ """ dict = process.extractOne(text.lower(), stops) if dict[1] > 75: text = dict[0] else: text = np.nan print("wait") return text def get_category_dataset(data): """ """ print("remap started. wait") data.text = data.text.map(lambda comment: get_category_from_comment(str(comment))) print("remap ends") data.dropna(inplace=True) data["text"] = data.text.map(lambda s: "" if s=="" else s) data["text"] = data.text.map(lambda s: "" if s=="" else s) data["text"] = data.text.map(lambda s: " " if s=="" else s) data["text"] = data.text.map(lambda s: " " if s=="" else s) return data
إخراج البيانات
الآن يمكننا أن نفترض أين ستكون وحدات التحكم على الأرجح في ساعة معينة.
نحن نبحث في سجلات البيانات الناتجة لمدة ساعة ويوم معين من الأسبوع. على سبيل المثال ، يوم الثلاثاء ، الساعة 9 صباحًا:
<code>data[(data["day_in_week"] == day) & (data["hour"] == hour)]</code>
(هذه ليست جميع البيانات)بعد ذلك ، نجد عدد نقاط التوقف الفريدة ، ونعرض فقط نقاط التوقف وعددها:
df[(df["day_in_week"] == 2) & (df["hour"] == 9)]["text"].value_counts()

الآن يمكننا أن نقول أنه في تمام الساعة التاسعة صباحًا ، يوم الثلاثاء ، من المرجح أن يتم رصد وحدات التحكم عند نقاط توقف Myasokombinat ، ul. Lugovaya ، BelGUT ، TD "Oma".
العيب الرئيسي في هذه الطريقة هو نقص البيانات. ليس لكل الأيام والساعات ، هناك إدخالات في التعليقات المقدمة خلال ساعة الذروة ، عندما يستخدم الناس وسائل النقل العام أكثر من البيانات في ساعات أقل شعبية ، ولكن إذا قمت بإضافة البيانات ، على سبيل المثال ، ليس فقط من تعليقات مجموعة واحدة ، ولكن أيضًا من المجموعات البديلة ، أو محادثات الدردشات البرقية ، مع عدد الإدخالات ، سيصبح كل شيء أسهل.
بوت مع VK LongPoll API
لإتاحة الفرصة لتلقي البيانات على موقع وحدات التحكم ، بناءً على الوقت ، وبدون ربطه بجهاز كمبيوتر ، قمت بعمل روبوت لمجموعة على فكونتاكتي تستجيب لأي رسالة عن طريق إرسال عدد التوقفات في السجلات ، بالنظر إلى الساعة واليوم الحاليين من الأسبوع.
رمز بوت from random import randint import vk_api from requests import * from get_stops_from_data import get_stops_by_time def start_bot(data, token): vk_session = vk_api.VkApi(token=token) vk = vk_session.get_api() print("bot started") longPoll = vk.groups.getLongPollServer(group_id=183524419) server, key, ts = longPoll['server'], longPoll['key'], longPoll['ts'] while True:
استنتاج
تم اختبار جودة هذه الفرضيات من قبلي أكثر من مرة في الممارسة ، وكل شيء يعمل بشكل جيد. اتضح أن وحدات التحكم ، في الأساس ، هي في المحطات نفسها ، على الرغم من أنه لا يمكن إعطاء تنبؤات صحيحة تمامًا ، واحتمال النجاح ليس 100٪. تشتمل مسافة Levenshtein على العديد من التطبيقات المختلفة ، بدءًا من تصحيح الأخطاء في كلمة واحدة ، مقارنة الجينات والكروموسومات والبروتينات ، ولكنها تنطوي أيضًا على إمكانات في مثل هذه المشكلات التطبيقية.
أتمنى لك يومًا سعيدًا وادفع الأجرة.
يتم نشر جميع التعليمات البرمجية وروبوتات التلاعب
هنا .