جابجایی دادهها – بررسی یک مشکل رایج در دنیای علم دادهها


اگر به مباحث مربوط به علم دادهها علاقهمند و خبرهای مختلف در این زمینه را دنبال کرده باشید، احتمالاً شنیدهاید که شرکت در مسابقات این حوزه علمی میتواند در یادگیری علم دادهها مفید باشد؛ درصورتیکه حل مسائل واقعی با مسائل مطرحشده در مسابقات متفاوت است.
یکی از تفاوتهای بین این دو، به کیفیت دادههای موجود برمیگردد. در مسابقات علم دادهها، مجموعه دادهها با دقت انتخاب و بررسی میشوند. معمولاً، یک مجموعه بزرگ از دادهها به فایل آموزش و آزمایش تقسیمبندی میشوند. بنابراین، فایل آموزش و آزمایش در اکثر مواقع از یک توزیع مشابه گرفته شدهاند.
در مسائل واقعی، مخصوصاً زمانی که دادهها در یک مدتزمان طولانی جمعآوری شده باشند، شرایط مسئله با مسابقات کاملاً متفاوت است. در چنین شرایطی، امکان چندین تغییر در متغیرها یا تغییر در محیط برداشت داده در طول زمان وجود دارد. در این صورت اگر توجه مناسبی به این مسئله نشود، مجموعه دادههای آموزش قادر به پیشبینی هیچ چیز قابل استفادهای راجع به دادههای آزمایش نخواهند بود.
در این مقاله، انواع مختلف مشکلات یا تغییر مجموعه دادههایی را خواهید دید که در مسائل واقعی علم داده رخ میدهد. به طور خاص، در این مقاله به توضیح یک نوع بخصوص از تغییر در مجموعه دادهها (تغییر متغیر کمکی)، روشهای موجود برای حل این نوع مشکل و تشریح یک روش خاص برای تصحیح این مشکل میپردازیم.
1. «جابجایی مجموعه دادهها» (Dataset Shift) چیست؟
اگر در یک مسابقه شرکت کنید، مراحل حل مسئله شما تقریباً مشابه با تصویر زیر خواهد بود.
بگذارید این مسئله را با کمک سناریوی نشان داده شده در تصویر زیر توضیح دهیم. در یک مسابقه، به شما یک فایل آزمایش و یک فایل آموزش داده میشود. شما فرآیندهای پیشپردازش، مهندسی ویژگی و اعتبارسنجی متقابل را بر روی مدل ساخته شده انجام میدهید اما نتیجهی مشابه ای با نتیجه به دست آمده در بخش اعتبارسنجی را به دست نمیآورید.
به نظر میرسد که مستقل از استراتژی اتخاذ شده برای اعتبارسنجی، نتایج شما در مقایسه با اعتبارسنجی، متفاوت خواهد بود.
اگر با دقت به تصویر اول نگاه کنید، متوجه خواهید شد که تمام تغییرات تنها با استفاده از فایل آموزش انجام شدهاند. بنابراین، اطلاعات موجود در فایل آزمایش بهکلی نادیده گرفته شدهاند. حال به تصویر دوم دقت کنید، متوجه خواهید شد که فایل آموزش حاوی اطلاعاتی راجع به افراد مذکر و مؤنث در سنین جوانی است درحالیکه فایل آزمایش حاوی اطلاعاتی راجع به افراد مسن است. این بدان معناست که دادههای موجود در فایل آموزش و آزمایش، به طور قابل توجهی متفاوت هستند.
بنابراین، اگر شما مدل خود را بر اساس مجموعه دادههایی حاوی اطلاعات افرادی با سن پایینتر بسازید و بخواهید اطلاعات مجموعه دادههایی با مقادیر سن بالاتر را پیشبینی کنید، مطمئناً به امتیاز پایینی دست خواهید یافت. دلیل این موضوع، وجود یک شکاف وسیع در علاقه و فعالیتهای بین این دو گروه است. درنتیجه، مدل شما در چنین شرایطی شکست خواهد خورد. به این تغییر در توزیع دادههای موجود در فایل آزمایش و آموزش را «تغییر مجموعه دادهها» (Dataset Shift) میگویند.
2. چه چیزی باعث جابجایی مجموعه دادهها میشود؟
اساساً در مسائل واقعی، جابجایی مجموعه دادهها به دلیل تغییر در محیط (محیط غیرثابت) رخ میدهد که این محیط میتواند به مکان، زمان و غیره اشاره داشته باشد.
به عنوان مثال، ما اطلاعات فروش اقلام مختلف در دوره زمانی تیرماه تا شهریورماه را جمعآوری کردیم. حال از شما میخواهیم تا میزان فروش در نوروز را برای ما پیشبینی کنید. نمایش تصویری فروش در فایل آموزش (خط آبی) و فایل آزمایش (خط مشکی)، شبیه به شکل زیر خواهد بود.
مطمئناً، فروش در مدت نوروز بسیار بیشتر از روزهای عادی خواهد بود. از اینرو، میتوان اظهار کرد که در این موقعیت، تغییر مجموعه دادهها رخ داده است و دلیل چنین مشکلی، تغییر در دوره زمانی بین فایل آزمایش و آموزش است. الگوریتمهای یادگیری ماشین (Machine Learning) ما، کار خود را بدون توجه به این تغییرات انجام میدهند. الگوریتمها فرض میکنند که محیطهای آزمایش و آموزش باهم مطابقت دارند و اگر چنین نباشد نیز تفاوتی در نتایج ایجاد نخواهد شد.
دو مثالی که در بالا زده شد را در نظر بگیرید. در مثال اول، تغییر در مقدار سن جمعیت (متغیر مستقل یا پیشگو) وجود داشت که همین باعث پیشبینی اشتباه نتایج شد. در مثال دوم، تغییر در میزان فروش (متغیر هدف) اقلام رخ داد. تفاوت بین این دو، موضوع انواع تغییر مجموعه دادهها را مطرح میکند که در بخش بعدی به آن میپردازیم.
3. انواع جابجایی مجموعه دادهها
تغییر مجموعه دادها را میتوان به سه نوع تقسیمبندی کرد:
- تغییر در متغیرهای مستقل (تغییر متغیر کمکی – Shift Covariate)
- تغییر در متغیرهای هدف (تغییر احتمال پیشین – Prior Probability Shift)
- تغییر در رابطه بین متغیر مستقل و متغیر هدف (تغییر مفهوم - Concept Shift)
در این مقاله، تنها به بررسی تغییر متغیر کمکی، روشهای تشخیص این تغییر و اقدامات مناسب برای بهبود پیشبینیها در چنین شرایطی میپردازیم. دو نوع دیگر از تغییر، هنوز هم در جمع حوزههای پژوهشی فعال هستند و هیچ راهحل قابل توجهی برای مقابله با آنها ارائه نشده است.
4. جابجایی متغیر کمکی
جابجایی متغیر کمکی به تغییر در توزیع متغیرهای ورودی موجود در دادههای آموزش و آزمایش اشاره میکند. این تغییر، رایجترین نوع جابجایی مجموعه دادهها است. ازآنجاییکه تقریباً تمام مجموعه دادههای واقعی از این مشکل رنج میبرند، این مسئله توجه بیشتری را به خود جلب کرده است.
در ابتدا، باید درک کنیم که چگونه تغییر در توزیع دادهها، باعث ایجاد مشکل برای ما میشود. به تصویر زیر نگاه کنید.
اگر با دقت به تصویر بالا نگاه کنید، متوجه میشوید که تابع آموزش تمایل دارد به دادههای آموزش برازش شود. با این حال، مشاهده میشود که توزیع آموزش و آزمایش باهم تفاوت دارند. از اینرو، استفاده از این تابع آموزش برای پیشبینی، قطعاً نتایج اشتباهی را در پی خواهد داشت. بنابراین، اولین مرحله، شناسایی تغییر در توزیع است.
5. شناسایی جابجایی دادهها
در این مرحله، از یک روش سریع و تقریبی یادگیری ماشین برای بررسی وجود جابجایی بین دادههای آموزش و آزمایش استفاده میکنیم.
ایده اصلی برای تشخیص جابجایی دادهها: اگر تغییری در مجموعه دادهها وجود داشته باشد، با ترکیب دادههای آزمایش و آموزش، باید همچنان قادر به طبقهبندی یک نمونه از مجموعه دادههای ترکیبشده (به عنوان آزمایش یا آموزش) با دقت مناسب باشید. به دلیل اینکه اگر ویژگیهای درون هر دو مجموعه داده، به توزیعهای متفاوتی تعلق داشته باشند، این ویژگیها باید بتوانند دادههای آزمایش و آموزش را به طور قابل توجهی از یکدیگر تفکیک کنند. بگذارید این مسئله را به صورت سادهتری توضیح دهیم. به توزیع ویژگی «id» در هر دو مجموعه داده نگاهی بیندازید.
در توزیعهای بالا، به وضوح مشاهده میشود که بعد از یک مقدار مشخص (30473)، تمامی نمونهها به مجموعه دادههای آزمایش تعلق خواهند داشت. بنابراین، مجموعه دادهای از ترکیب نمونههای آزمایش و آموزش را ایجاد کردهایم که پیش از ترکیب، نمونه دادههای آموزش، با عنوان «آموزش» و نمونه دادههای آزمایش، با عنوان «آزمایش» برچسبگذاری شدهاند. در این مجموعه دادههای جدید، اگر به ویژگی «id» نگاه کنیم، میتوانیم هر نمونهی متعلق به دادههای آزمایش و آموزش را به طور مشخص طبقهبندی کنیم. بنابراین، میتوان نتیجه گرفت که «id»، یک ویژگی تغییر یافته و جابهجا شده برای این مجموعه داده است.
این روش تقریباً راحت است اما نمیتوان تمام متغیرها را رسم کرده و بررسی کرد که آیا جابجا شدهاند یا خیر. به این منظور، میتوان این روند را به صورت یک مسئله ساده طبقهبندی در پایتون (Python) کدنویسی و ویژگیهای جابجا شده را شناسایی کرد.
مراحل شناسایی جابجایی: مراحل اصلی شناسایی جابجایی، به صورت زیر است:
- مرحله اول پیشپردازش است. این مرحله شامل تخصیص تمام مقادیر از دست رفته و برچسبگذاری تمام «متغیرهای رستهای» (Categorical Variables) میشود.
- ایجاد یک نمونه تصادفی از دادههای آزمایش و آموزش به صورت جداگانه و اضافه کردن یک منبع ویژگی جدید که مقادیر آزمایش یا آموزش آن، بسته به منشأ مشاهدات (مجموعه دادههای آزمایش یا آموزش) تعیین شده باشد.
- ترکیب نمونههای تصادفی درون یک مجموعه داده واحد. توجه داشته باشید که شکل هر دو نمونهی مجموعه دادههای آزمایش و آموزش باید تقریباً مساوی باشد و در غیر این صورت، امکان مواجه با مجموعه دادههای نامتوازن وجود خواهد داشت.
- اکنون باید یک مدل را با استفاده از دریافت ویژگیها به صورت یکبهیک ایجاد کرد. منبع ویژگیها، به عنوان متغیر هدف در بخشی از مجموعه دادهها در نظر گرفته میشود (مثلاً 75 درصد مجموعه).
- در این مرحله، باید بخش باقیمانده مجموعه را پیشبینی (25 درصد باقیمانده) و مقدار منحنی مشخصه عملکرد و سطح زیر منحنی (AUC-ROC) را محاسبه کرد.
- بعد از انجام مرحله قبل، اگر AUC-ROC برای یک ویژگی بخصوص، بزرگتر از 0.80 شد، آن ویژگی را به عنوان ویژگی جابجا شده طبقهبندی میکنیم.
توجه کنید که در اینجا مقدار 0.8 را به عنوان مقدار آستانه در نظر گرفته شد اما این مقدار میتواند با توجه به شرایط تغییر کند.
برای شناسایی ویژگیهای جابجا شده در مسائل، میتوانید از کد پایتون زیر استفاده کنید.
## importing libraries import numpy as np import pandas as pd from pandas import Series, DataFrame import os import matplotlib.pyplot as plt get_ipython().magic('matplotlib inline') os.chdir('/media/shubham/3AA25FBFA25F7DF7/Kaggle/russian housing market') from sklearn.ensemble import RandomForestRegressor from sklearn.ensemble import RandomForestClassifier from sklearn.cross_validation import cross_val_score from sklearn.preprocessing import LabelEncoder ## reading files train = pd.read_csv('train.csv') test = pd.read_csv('test.csv') #### preprocessing #### ## missing values for i in train.columns: if train[i].dtype == 'object': train[i] = train[i].fillna(train[i].mode().iloc[0]) if (train[i].dtype == 'int' or train[i].dtype == 'float'): train[i] = train[i].fillna(np.mean(train[i])) for i in test.columns: if test[i].dtype == 'object': test[i] = test[i].fillna(test[i].mode().iloc[0]) if (test[i].dtype == 'int' or test[i].dtype == 'float'): test[i] = test[i].fillna(np.mean(test[i])) ## label encoding number = LabelEncoder() for i in train.columns: if (train[i].dtype == 'object'): train[i] = number.fit_transform(train[i].astype('str')) train[i] = train[i].astype('object') for i in test.columns: if (test[i].dtype == 'object'): test[i] = number.fit_transform(test[i].astype('str')) test[i] = test[i].astype('object') ## creating a new feature origin train['origin'] = 0 test['origin'] = 1 training = train.drop('price_doc',axis=1) #droping target variable ## taking sample from training and test data training = training.sample(7662, random_state=12) testing = test.sample(7000, random_state=11) ## combining random samples combi = training.append(testing) y = combi['origin'] combi.drop('origin',axis=1,inplace=True) ## modelling model = RandomForestClassifier(n_estimators = 50, max_depth = 5,min_samples_leaf = 5) drop_list = [] for i in combi.columns: score = cross_val_score(model,pd.DataFrame(combi[i]),y,cv=2,scoring='roc_auc') if (np.mean(score) > 0.8): drop_list.append(i) print(i,np.mean(score))
# Drifting features : {id, life_sq, kitch_sq, hospital_beds_raion, cafe_sum_500_min_price_avg, cafe_sum_500_max_price_avg, cafe_avg_price_500 }
به عنوان مثال، پس از اجرای کد بالا، هفت ویژگی جابجا شده یافت شد. شما میتوانید با استفاده از تصویرسازی و استفاده از تحلیل واریانس یکطرفه (One-Way ANOVA) نیز تفاوت بین توزیعها را بررسی کنید. سؤالی که پس از شناسایی چنین مشکلی پیش میآید این است که «برای بهبود پیشبینی خود، چه کاری باید انجام دهیم؟»
6. برطرف کردن مشکل
تکنیکهای متنوعی برای مقابله با مسئله ویژگیهای جابهجاشده و بهبود مدل وجود دارند. در ادامه به توضیح دو مورد از آنها میپردازیم:
- حذف ویژگیهای جابهجاشده
- اختصاص ضریب اهمیت با استفاده از «تخمین چگالی نسبی» (Density Ratio Estimation)
1.6. حذف ویژگیهای جابهجا شده
این روش تقریباً آسان است. در این روش، ویژگیهایی که به عنوان ویژگیهای جابهجا شده طبقهبندی شده باشند را حذف میکنیم. باید توجه داشته باشیم که با حذف ویژگیها، امکان از دست رفتن برخی اطلاعات نیز وجود دارد. برای حل این مسئله، یک قانون ساده تعریف میکنیم. ما تنها ویژگیهایی را حذف میکنیم که مقدار جابجایی آنها بالاتر از 0.8 بوده و اهمیت بالایی نداشته باشند.
برای تعیین اهمیت ویژگیها، از روش جنگل تصادفی استفاده شد. کدهای این روش در ادامه آورده شدهاند.
# using a basic model with all the features training = train.drop('origin',axis=1) testing = test.drop('origin',axis=1) rf = RandomForestRegressor(n_estimators=200, max_depth=6,max_features=10) rf.fit(training.drop('price_doc',axis=1),training['price_doc']) pred = rf.predict(testing) columns = ['price_doc'] sub = pd.DataFrame(data=pred,columns=columns) sub['id'] = test['id'] sub = sub[['id','price_doc']] sub.to_csv('with_drifting.csv', index=False)
خطای جذر میانگین مربعات برای فهرست اهمیت ویژگیها، مقدار 0.40116 به دست آمد. برای بررسی 20 ویژگی مهمتر در این مدل، از کد زیر استفاده میکنیم.
### plotting importances features = training.drop('price_doc',axis=1).columns.values imp = rf.feature_importances_ indices = np.argsort(imp)[::-1][:20] #plot plt.figure(figsize=(8,5)) plt.bar(range(len(indices)), imp[indices], color = 'b', align='center') plt.xticks(range(len(indices)), features[indices], rotation='vertical') plt.xlim([-1,len(indices)]) plt.show()
حال اگر فهرست ویژگیهای حذفشده را با فهرست ویژگیهای مهم مقایسه کنیم، متوجه میشویم که ویژگیهای «life_sq» و «kitch_sq» در هر دو فهرست وجود دارند. بنابراین، این دو ویژگی را در درون مدل خود نگه میداریم و باقی را حذف میکنیم.
توجه: قبل از حذف هر ویژگی، اطمینان حاصل کنید آیا امکان ایجاد یک ویژگی جدید از آن وجود دارد یا خیر.
برای بررسی کارایی این روش در بهبود نتایج پیشبینی، کد زیر را اجرا میکنیم.
## dropping drifting features which are not important. drift_train = training.drop(['id','hospital_beds_raion','cafe_sum_500_min_price_avg','cafe_sum_500_max_price_avg','cafe_avg_price_500'], axis=1) drift_test = testing.drop(['id','hospital_beds_raion','cafe_sum_500_min_price_avg','cafe_sum_500_max_price_avg','cafe_avg_price_500'], axis=1) rf = RandomForestRegressor(n_estimators=200, max_depth=6,max_features=10) rf.fit(drift_train.drop('price_doc',axis=1),training['price_doc']) pred = rf.predict(drift_test) columns = ['price_doc'] sub = pd.DataFrame(data=pred,columns=columns) sub['id'] = test['id'] sub = sub[['id','price_doc']] sub.to_csv('without_drifting.csv', index=False)
خطای جذر میانگین مربعات برای فهرست اهمیت ویژگیها، مقدار 0.39759 به دست آمد. همانطور که مشاهده میشود، عملکرد مدل ما با استفاده از روش حذف ویژگیهای جابهجاشده بهبود یافت.
2.6. اختصاص ضریب اهمیت با استفاده از تخمین چگالی نسبی
در این روش، ابتدا چگالی دادههای آزمایش و آموزش به صورت جداگانه تخمین زده شده و سپس، با توجه به چگالیهای نسبی تخمین زده شده برای دادههای آزمایش و آموزش، ضریب اهمیت ویژگیها را محاسبه میشود. چگالیهای به دست آمده، به عنوان وزن یا ضریبی برای نمونههای موجود در دادههای آموزش استفاده خواهند شد. نکته قابل توجه این است که اختصاص وزن دهی به تکتک نمونهها بر اساس چگالی نسبی، کار دشواری خواهد بود (مخصوصاً در مجموعه دادههایی با ابعاد بالاتر).
فرآیند محاسبه چگالی نسبی یک ویژگی در سیستمی با پردازنده i7 به همراه حافظه رم 128 گیگابایت، حدود 3 دقیقه زمان برد. علاوه بر این، هیچ بهبودی در امتیاز وزن دهی دادههای آموزش حاصل نشد. مطمئناً، انجام این روش برای مجموعه دادهای با 200 ویژگی، کار بسیار زمانبری خواهد بود. بنابراین، این روش فقط برای اهداف تحقیقاتی مناسب است. کاربرد این روش در مسائل واقعی هنوز قابل بحث بوده و یک حوزه پژوهشی فعال به حساب میآید.
7. سخن پایانی
امیدواریم که با مطالعه این مقاله، به درک بهتری از جابجایی و تغییر دادهها، نحوه شناسایی و برطرف کردن مؤثر آنها دست یافته باشید. این مشکل، به یکی از رایجترین مشکلات موجود در مجموعه دادههای واقعی تبدیل شده است. بنابراین، باید همیشه در هنگام حل مسائل، وجود یا عدم وجود این مشکل را بررسی کنید. مطمئناً چنین کاری، تأثیر مثبتی بر روی نتایج شما خواهد داشت.