گزارش تحلیل احساسات کامنت‌های آمازون برای محصولات الکسا با ۹۳درصد دقت

3000 Amazon comments, Sentiment Analysis with 93% accuracy
3000 Amazon comments, Sentiment Analysis with 93% accuracy


تحلیل احساسات، که به اون نظرکاوی (Opinion Mining) یا هوش مصنوعی احساسات (Emotion AI) هم گفته می‌شه، به استفاده از پردازش زبان طبیعی برای تشخیص، استخراج و مطالعه متن‌های نوشته شده توسط افراد گفته می‌شه.

یکی از دیتاست‌هایی که برای آموزش معمولا ازش استفاده می‌شه و در واقع از داده‌های آموزشی کگل هستش، داده‌های مربوط به نظرات خریداران محصولات الکسا از آمازون هست. هدف این هستش که با استفاده از اجرای یک الگوریتم یادگیری ماشین روی داده‌های آموزشی، بتونیم با وارد شدن هر نظر جدیدی بفهمیم اون مشتری از محصول راضی بوده یا نه.

در ادامه قدم به قدم با این دیتاست آشنا می‌شیم و بعد از آماده‌سازی و کمی مصورسازی، با استفاده از الگوریتم Random Forest تسک پیش‌بینی راضی یا ناراضی بودن مشتری از روی کامنتش رو به انجام می‌رسونیم.

قدم اول:‌ بررسی داده‌ها

اول از همه بیاید ببینیم چه داده‌های در اختیار داریم:

(من نوت‌بوکم رو توی کگل آپلود کردم و لینکش رو در انتهای مطلب قرار دادم، به خاطر همین از کدهای ساده مثل ایمپورت کردن داده و رسم نمودارها صرفه‌نظر می‌کنم و فقط بعضی از بخش‌ها که مربوط می‌شه به تنظیمات الگوریتم رو اینجا میارم.)

داده‌های کامنت‌های خریدارن که از آمازون داریم شامل ۵ تا فیلد هست: رنک یا امتیازی که مشتری به محصول داده، تاریخ نوشته شدن کامنت، نظر تایید شده، نوع محصول و در آخر فیدبک که همون فیلد هدف ما هستش و مشخص می‌کنه که آیا مشتری راضی بوده یا نه (کلاس ۰ مشتری ناراضی و کلاس ۱ مشتری راضی).


اول از همه بیاید ببینیم اصلا چند تا مشتری راضی و چند تا مشتری ناراضی داریم:

از مجموع ۳۱۴۹ نظر، طبق فیلد فیدبک، ۲۸۹۳ مشتری راضی و ۲۵۷ مشتری ناراضی بودن (امیدوارم بایاسی در قبول کردن نظرات منفی وجود نداشته بوده باشه :) )

یعنی ۹۱.۸درصد مشتری‌ها راضی و فقط ۸.۲درصد ناراضی بودن.



از تعداد نظرات مثبت و منفی می‌شه فهمید که دو تا کلاس مشتری راضی و ناراضی ما به شدت نامتوازن هستند و از بعضی از الگوریتم‌ها مثل بیز نمی‌تونیم استفاده کنیم و موقع استفاده از الگوریتم‌هایی مثل رندم فارست هم با تعریف کردن وزن برای کلاس مینور می‌تونیم بخشی از این عدم توازن رو خنثی کنیم.

در بین رنک‌هایی که افراد دادن هم می‌شه دید که بیشتر نظرات مربوط به مشتری‌های راضی هستند:


بریم ببینم آیا نوع محصول فروخته شده از بین محصولات الکسا تاثیری داشته توی رای مشتری:


خب به نظر می‌رسه که اطلاعات زیادی از نوع محصول و رضایت مشتری به دست نیاد و بشه گفت که در تمام انواع محصولات میزان رضایت تفاوت چندانی نداشته. پس احتمالا ایده بدی نباشه که از مدل خارجشون کنیم. البته فعلا نگه‌شون می‌داریم که بعدا می‌تونیم برای تست نبودنشون رو هم امتحان کنیم روی نتیجه کار.

یه مورد شهودی که می‌تونیم تست کنیم و اگه معنادار بود به عنوان یک شاخص اضافه‌ش کنیم، طول کامنت‌های مثبت و منفیه.

برای بررسی این موضوع، طول کامنت‌ها رو حساب‌ می‌کنیم و بعد با نمودار KDE با استفاده از دو تا نمودار مختلف از طول کامنت‌های با فیدبک مثبت و منفی مقایسه رو انجام می‌دیم.


نمودار KDE از کتابخونه seaborn، نموداری مشابه هیستوگرام هستش، با این تفاوت که هیستوگرام تابع چگالی رو تخمین می‌زنه و بعد با تقسیم کردن داده به بخش‌هایی یا به اصطلاح bins، و شمردن تعداد مشاهده‌ها در هر bin، نمودار رو رسم می‌کنه. اما Kernel Density Estimation به اختصار KDE روشی متفاوت برای این کار داره؛ به این صورت که به جای استفاده از بخش‌های گسسته، با استفاده از یک کرنل گوسی، مشاهدات رو به اصطلاح smooth می‌کنه و یه تخمین از چگالی احتمال رو به صورت پیوسته تولید می‌کنه.

نمودارها رو به با استفاده از کد زیر رسم می‌کنیم:

plt.figure(figsize=(14, 8))
l = sns.kdeplot(df_alexa[&quotlength&quot][(df_alexa[&quotfeedback&quot] == 0)], color=&quotRed&quot, shade = True)
l = sns.kdeplot(df_alexa[&quotlength&quot][(df_alexa[&quotfeedback&quot] == 1)], ax =l, color=&quotBlue&quot, shade= True)
l.set_xlabel(&quotlength&quot)
l.set_ylabel(&quotFrequency&quot)
l = l.legend([&quotFeedback=0&quot,&quotFeedback=1&quot])


همونطور که مشاهده می‌کنید طول کامنت‌های مثبت بین ۰ تا ۳۰۰ و طول کامنت‌های منفی بین ۰ تا ۵۰۰ هستش. پس می‌تونیم نتیجه بگیریم که ارتباط معناداری بین طول کامنت و مثبت یا منفی بودن کامنت وجود داره و بهتره که فیلد طول کامنت‌ها هم به داده‌های ورودی‌مون اضافه کنیم.

آماده‌سازی داده

قبل از هر کاری لازمه که چک کنیم ببینیم missing value یا رکوردهای ناقص داریم یا نه. با یه دستور ساده می‌تونیم این موضوع رو بررسی کنیم:


به نظر می‌رسه داده‌ها به طور کامل ثبت شدن و نیازی نیست که کاری در این مورد انجام بدیم خوشبختانه. و از اونجایی که تمام فیلدهامون هم از جنس Nominal هستن، نیازی نیست که به فکر داده‌های پرت باشیم.

برای آموزش دادن الگوریتم، به یه مرحله دیگه هم نیاز داریم که کدگذاری داده‌های تکست هستش که بتونه برای الگوریتم قابل فهم باشه. برای این کار از متد get_dummies استفاده می‌کنیم. به این معنی که هر رکوردی که در دسته‌بندی یک نوع خاص از محصول قرار می‌گیره، فیلد مربوط به اون گزینه عدد ۱ و بقیه گزینه‌ها عدد صفر رو می‌گیرن. توی شکل پایین بیشتر مشخصه:


حالا وقتشه که تمام کلمات استفاده شده در نظرها رو استخراج کنیم، در یک آرایه ذخیره کنیم، توی دیتافریم جاگذاریش کنیم و بعد با ران کردن رندم فارست بتونیم ارتباط بین نظرات و رضایت مشتری رو متوجه بشیم.

قدم اول اینکه که متن‌ها رو استخراج کنیم. برای این کار:

from sklearn.feature_extraction.text import CountVectorizer
vectorizer = CountVectorizer()
alexa_vectorizer = vectorizer.fit_transform(df_alexa['verified_reviews'])

آرایه‌ی متن‌های کلمات شده به صورت زیر هست:


حالا لازمه کلمات استخراج شده رو به صورت صفر و یک کد گذاری کنیم، به دیتاست اضافه‌ش کنیم و ستون مربوط به کامنت‌ها که به صورت متنی بود رو از دیتاست حذف کنیم:

encouded_reviews = pd.DataFrame(alexa_vectorizer.toarray())
df_alexa.drop(['verified_reviews'], axis = 1, inplace = True)
df_alexa = pd.concat([df_alexa, encouded_reviews], axis = 1)

هنوز چند مرحله دیگه مونده که بتونیم الگوریتم رندم فارست رو روی داده‌ها اجرا کنیم.

لازمه که فیلد تارگت رو از سایر فیلدها جذا کنیم. و در مرحله بعد داده‌های test و train رو از همدیگه جدا کنیم.

X = df_alexa.drop(['feedback'], axis = 1)
Y = df_alexa['feedback']
from sklearn.model_selection import train_test_split
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size = 0.25, random_state = 15)

برای شروع می‌تونیم داده‌های تست رو ۲۵درصد و رندم استیت رو ۱۵ انتخاب کنیم و بعد از ران گردن الگوریتم تست کنیم که با اعداد دیگه چه نتیجه‌ای به دست خواهیم آورد.

معیارهایی که برای سنجش نتایج لازم داریم و الگوریتمون رو ایمپورت می‌کنیم:

from sklearn.metrics import confusion_matrix, classification_report
from sklearn.ensemble import RandomForestClassifier
randomforest_classifier = RandomForestClassifier(n_estimators =25, criterion = 'entropy', class_weight={0:8, 1: 1})

همونطور که می‌دونید رندم فارست یکی از مدل‌های ensemble است که حاصل نتایج چند درخت رو با هم ترکیب می‌کنه و ارائه می‌ده. شاخصی که انتخاب شده برای جدا کردن شاخه‌ها، آنتروپی هست،۲۵ درخت تصمیم ران می‌شن و همونطور که قبل‌تر گفتم چون کلاس‌ها فیدبک به شدت نامتوازن هستند، وزن‌ ۶ رو برای کلاس ۰ و وزن ۱ رو برای کلاس ۱ درنظر می‌گیریم. البته من چند با تست کردم و این اعداد بهترین نتایج رو می‌دادن.

ران کردن الگوریتم

حالا وقتشه که الگوریتمون رو با داده‌های train‌ آموزش بدیم:

randomforest_classifier.fit(X_train, Y_train)

و بعد با استفاده از الگوریتم آموزش‌دیده، فیدبک رو برای داده‌های تست مورد بررسی قرار بدیم:

Y_t_P = randomforest_classifier.predict(X_train)

بررسی نتایج

می‌رسیم به قسمت هیجان انگیز ماجرا: یعنی بررسی اینکه مدلمون چقدر دقت داشته! این کار رو با استفاده از confusion matrix انجام می‌دیم.

ماتریس confusion یا درهم‌ریختگی برای داده‌های آموزشی:


ماتریس confusion یا درهم‌ریختگی برای داده‌های تست:


خب، نتایجی که به دست آوردیم بد هم نبودن! تونیستیم با محاسباتی ساده به دقت ۹۳ درصد برسیم. قطعا می‌شه بهترش کرد؛ ولی هدف از این مطلب یه گزارش ساده از یه پروژه آموزشی بود و بهتره بریم سراغ پروژه‌های دیگه. .

لینک نوت‌بوک در کگل:

https://www.kaggle.com/maryamnaaseri/alexa-amazon-sentiment

خیلی خوشحال می‌شم اگه جایی اشکالی دیدین بهم بگی که اصلاح کنم.