لینک به ویدئوی این درس (یوتیوب)
در مواردی ممکن است دیتایی داشته باشیم که دارای مقادیر ناقص باشد که اصطلاحا به آن missing values میگوییم. در ادامه این پست بلاگ میخواهیم نحوه مدیریت این پدیده را بررسی کنیم.
در پایان این نوشته قادر خواهیم بود مقادر از دست رفته یا missing values را مدیریت کنیم. فرمت داده صحیحی انتخاب کنیم و همچنین دادههای خود را استاندارد و نرمالسازی کنیم.
هدف از data cleaning تغییر وضعیت دیتای اولیه به حالتی است که بتوان آن را بهتر آنالیز نمود.
فراخوانی
در ابتدا کتابخانههای مورد نظر را فراخوانی میکنیم:
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
با دستور زیر دیتا را میخوانیم:
df = pd.read_csv('missed.txt')
EDA
حال با دستورhead یه نگاه اجمالی به دادههای خود میاندازیم و همچنین با describe مقادیر مرتبط با میانگین و مد و … را در مورد دیتای خود میبینیم و با دستور info نوع داده و تعداد مقادیر ناموجود را مشاهده میکنیم:
df.head()
df.describe()
df.info()
حال با دستور زیر مقادیر یکتای هر ستون از دیتا را مشاهده خواهیم کرد:
() df['normalized-losses'].unique
حال اگر بخواهیم مقادیر یکتای تمام ستونها را مشاهده کنیم، از حلقه استفاده میکنیم:
for i in headers:
print('-----------')
print(i)
print(df[i].unique())
با اجرای حلقه فوق مشاهده میکنیم که در برخی از ستونها مقادیر نامشخص با علامت ? وجود دارد. این مقادیر همان مقادیرmissing value هستند که ممکن است روند تحلیل داده ما را تحت تاثیر قرار دهند. با هدف افزایش سرعت محاسبات، در ابتدا مقادیر ? را با nan null جایگزین میکنیم.
import numpy as np
df.replace("?", np.nan, inplace = True)
df.head(5)
df.info()
مدیریت Missing values:
یکی از راههای مدیریت missing values حذف مقادیر است که به طرق زیر امکانپذیر میباشد:
- . Drop the whole row
- . Drop the whole column
جایگذاری روش دیگری است که ممکن است یکی از راههای زیر به کار رود:
- . Replace it by mean -یعنی جایگزاری با مقدار میانگین
- . Replace it by frequency
- جایگذاری متناسب با تکرار؛ مثلا اینکه پر تکرارترین داده را بعنوان مقدار جایگزین انتخاب کنیم.
- . Replace it based on other functions –
با دستور زیر میبینیم که سطرهایی که مقادیر صفر دارند، حذف میشوند. تعداد سطرهای باقی مانده 159 سطر است. با توجه به اینکه در ابتدا 205 سطر داشتهایم، متوجه میشویم که تعداد 46 سطر ما حذف شده است و این درصد زیادی از دادهها را در بر میگیرد(حدود 25 درصد دادههای ما حذف شده است).
df.dropna(axis=0)
در دستور بعدی ستونهایی که مقادیر صفر دارند را حذف میکنیم و میبینیم که تنها 19 ستون باقی میماند:
df.dropna(axis=1)
بنابراین حذف داده، همیشه روش مناسبی برای مدیریت دادههای گم شده نیست.
اگر مقادیر عددی باشند، یکی از روشهای مناسب برای مدیریت دادههای گم شده، جایگذاری با مقدار میانگین است. برای مثال با وارد کردن دستور df.info() میبینیم که ستون موسوم به normalised-losses تنها دارای 164 مقدار است و تعداد 205-164 مقدار آن وجود ندارد.
با فرض اینکه در مورد این ردیف دانش داریم و میدانیم که نوع داده آن از نوع عددی هستند، اقدام به جایگذاری آن با مقادیر میانگین میکنیم. اما ابتدا باید نوع داده این ردیف را از نوع object به float تبدیل کنیم. (به دلیل اینکه دادهها از منابع مختلف جمعآوری شده است، نوع داده در حالت obj ذخیره شده است. اما میدانیم که دادههای این ستون عدد هستند. پس باید به نوع int یا float تبدیل گردد.) از متود astype استفاده میکنیم.
میانگین:
در خط دوم کد زیر از دادهها میانگین میگیریم:
avg_norm_loss_float =df["normalized-losses"].astype("float")
avg_norm_loss= avg_norm_loss_float.mean()
print('avg_norm_loss=',avg_norm_loss)
حال با دستور زیر مقادیر nan را با مقادیر میانگین جایگذاری میکنیم:
df["normalized-losses"].replace\
(np.nan, avg_norm_loss, inplace=True)
بعد از دستور بالا اگر df.info بگیریم، میبینیم که تعداد مقادیر Non-nul عدد کامل 205 را نشان میدهد و این یعنی مقادیر جایگزین شده است و این یعنی دیگر خیالمان بابت ستون normalized-losses راحت شده است.
این کار را برای سایر مقادیر نیز انجام میدهیم(بعنوان تمرین):
ave_stroke = df['stroke'].astype('float').mean(axis=0)
print("Average stroke:", ave_stroke)
---
avg_bore=df['bore'].astype('float').mean(axis=0)
print("Average of bore:", avg_bore)
---
ave_horsepower = df['horsepower'].astype('float').mean(axis=0)
print("Average horsepower:", ave_horsepower)
---
ave_peak_rpm = df['peak-rpm'].astype('float').mean(axis=0)
print("Average peak_rpm:", ave_peak_rpm)
---
حال با دستورات زیر مقادیر میانگین بدست آمده را جایگزین میکنیم:
df["stroke"].replace(np.nan, ave_stroke, inplace=True)
df["bore"].replace(np.nan, avg_bore, inplace=True)
df["horsepower"].replace(np.nan,ave_horsepower, inplace=True)
df["peak-rpm"].replace(np.nan, ave_peak_rpm, inplace=True)
حال به سراغ دیتاهای دستهبندی شده میرویم. با دستور زیر میخواهیم ببینیم از هر دسته چه تعداد وجود دارد:
df['num-of-doors'].value_counts()
از جواب کد بالا مشخص است که ماشینهای 4 درب رایجترین خودروها هستند.خودروهای چهار درب 114 تا هستند و دو دربها 89 تا . پس جاهای خالی را با چهار پر میکنیم. همچنین با دستور زیر میتوان تعداد مقادیر پرتکرار را پیدا کرد و مقادیر nan را با آن جایگذاری کرد:
df['num-of-doors'].value_counts().idxmax()
df["num-of-doors"].replace(np.nan, "four", inplace=True)
ستون آخر قیمت را مشخص میکند. حال میتوان آن مواردی را که قیمت ندارند را حذف نمود. زیرا وقتی قیمت نداشته باشیم، دادههای ستونهای مرتبط با آن به هیچ وجه به درد ما نخواهند خورد. (چرا؟)
# simply drop whole row with NaN in "price" column
df.dropna(subset=["price"], axis=0, inplace=True)
# reset index, because we droped two rows
df.reset_index(drop=True, inplace=True)
df.head()
df.info()
حالا دیتایی داریم که هیچگونه missing values نداشته و برای آنالیز کردن آماده هستند.
فرمت داده صحیح:
آخرین مرحله از data cleaning بررسی این مورد است که نوع داده ما در حالت صحیحی باشند. در کتابخانه پانداس از دو دستور زیر برای تشخیص و تغییر نوع داده استفاده میشود:
dtype : برای چک کردن نوع داده
astype : برای تغییر نوع داده
با دستور زیر نوع داده هر ستون را مشخص میکنیم:
df.dtypes
همانگونه که میبینیم، نوع برخی از دادهها در حالت صحیحی قرار ندارند. برای مثال دادههای عددی باید در حالت float یا Int باشند. و یا اینکه دادههای categorical باید در حالت object باشند. اما برای مثال دو ستون bore وstroke که مربوط به engine هستند، انتظار میرود که دادههای عددی باشند، اما میبینیم که به صورت object نمایش داده شدهاند. در این چنین مواردی ما باید با استفاده از دستور astype نوع داده را به فرمت صحیح تبدیل کنیم:
df[["bore", "stroke","peak-rpm","price"]] = df[["bore", "stroke","peak-rpm","price"]].astype("float")
df[["normalized-losses"]] = df[["normalized-losses"]].astype("int")
سپس مجددا نوع دادهها را بررسی میکنیم:
df.dtypes
در نتیجه دستور بالا مشاهده میکنیم که همه دادهها در فرمت صحیح قرار دارند. کار data cleaning ما در اینجا به پایان میرسد. در مرحله بعد میخواهیم دیتا ها را استانداردسازی کنیم.
نوشته بعدی: داده های استاندارد شده
منبع:
1- یوتیوب مونا حاتمی لینک
2-گیت هاب monogram
3-گیت هاب Strumer -learn ML