數(shù)據(jù)分析:帶你零基礎(chǔ)入門數(shù)據(jù)挖掘(附代碼)(數(shù)據(jù)挖掘入門教程)

數(shù)據(jù)分析:帶你零基礎(chǔ)入門數(shù)據(jù)挖掘(附代碼)(數(shù)據(jù)挖掘入門教程)

來源:Datawhale

本文約4200字,建議閱讀9分鐘

對于數(shù)據(jù)挖掘項目,本文將學(xué)習(xí)應(yīng)該從哪些角度分析數(shù)據(jù)?如何對數(shù)據(jù)進行整體把握,如何處理異常值與缺失值,從哪些維度進行特征及預(yù)測值分析?

標(biāo)簽:數(shù)據(jù)挖掘

探索性數(shù)據(jù)分析(Exploratory Data Analysis,EDA)是指對已有數(shù)據(jù)在盡量少的先驗假設(shè)下通過作圖、制表、方程擬合、計算特征量等手段探索數(shù)據(jù)的結(jié)構(gòu)和規(guī)律的一種數(shù)據(jù)分析方法。

數(shù)據(jù)及背景

阿里天池-零基礎(chǔ)入門數(shù)據(jù)挖掘

https://tianchi.aliyun.com/competition/entrance/231784/information

EDA的目標(biāo)

  • 熟悉數(shù)據(jù)集,了解數(shù)據(jù)集,對數(shù)據(jù)集進行驗證來確定所獲得數(shù)據(jù)集可以用于接下來的機器學(xué)習(xí)或者深度學(xué)習(xí)使用。
  • 了解變量間的相互關(guān)系以及變量與預(yù)測值之間的存在關(guān)系。
  • 引導(dǎo)數(shù)據(jù)科學(xué)從業(yè)者進行數(shù)據(jù)處理以及特征工程步驟的重視,使數(shù)據(jù)集的結(jié)構(gòu)和特征集讓接下來的預(yù)測問題更加可靠。

數(shù)據(jù)載入及總覽

載入各種數(shù)據(jù)科學(xué)以及可視化

missingno庫用于可視化缺失值分布,是基于matplotlib,接受pandas數(shù)據(jù)源

import pandas as pdimport numpy as npimport matplotlib.pyplot as pltimport seaborn as snsimport missingno as msno # 用于可視化缺失值分布import scipy.stats as st

載入數(shù)據(jù)

path = './data/'Train_data = pd.read_csv(path 'used_car_train_20200313.csv', sep=' ')Test_data = pd.read_csv(path 'used_car_testA_20200313.csv', sep=' ')

所有特征集均脫敏處理,脫敏處理后均為label encoding形式,即數(shù)字形式:

數(shù)據(jù)分析:帶你零基礎(chǔ)入門數(shù)據(jù)挖掘(附代碼)(數(shù)據(jù)挖掘入門教程)

總覽數(shù)據(jù)

簡略觀察數(shù)據(jù)head() shape

Train_data.head().append(Train_data.tail())Test_data.head().append(Test_data.tail())Train_data.shapeTest_data.shape

describe()熟悉相關(guān)統(tǒng)計量

describe()中包含每列的統(tǒng)計量,個數(shù)(count)、平均值(mean)、方差(std)、最小值(min)、中位數(shù)(25% 50% 75%)、最大值(max)等。通過觀察以上指標(biāo),可以瞬間掌握數(shù)據(jù)的大概范圍和每個值的異常值的判斷 ,例如有時候會發(fā)現(xiàn)999 9999、 -1 等值這些其實都是nan的另外一種表達方式。

Train_data.describe()

數(shù)據(jù)分析:帶你零基礎(chǔ)入門數(shù)據(jù)挖掘(附代碼)(數(shù)據(jù)挖掘入門教程)

info()熟悉數(shù)據(jù)類型

通過info()來了解數(shù)據(jù)每列的type,有助于了解是否存在除了nan以外的特殊符號異常。

Train_data.info()

數(shù)據(jù)分析:帶你零基礎(chǔ)入門數(shù)據(jù)挖掘(附代碼)(數(shù)據(jù)挖掘入門教程)

缺失值和異常值

缺失值

查看每列的存在nan情況Train_data.isnull().sum()Test_data.isnull().sum()

數(shù)據(jù)分析:帶你零基礎(chǔ)入門數(shù)據(jù)挖掘(附代碼)(數(shù)據(jù)挖掘入門教程)

排序函數(shù)sort_values()

可以將數(shù)據(jù)集依照某個字段中的數(shù)據(jù)進行排序,該函數(shù)即可根據(jù)指定數(shù)據(jù)列也可根據(jù)指定行的

數(shù)據(jù)分析:帶你零基礎(chǔ)入門數(shù)據(jù)挖掘(附代碼)(數(shù)據(jù)挖掘入門教程)

通過以下兩句可以很直觀的了解哪些列存在 “nan”, 并可以把nan的個數(shù)打印。主要的目的在于 nan存在的個數(shù)是否真的很大,如果很小一般選擇填充,如果使用lgb等樹模型可以直接空缺,讓樹自己去優(yōu)化,但如果nan存在的過多、可以考慮刪掉。

# nan可視化missing = Train_data.isnull().sum()missing = missing[missing > 0]missing.sort_values(inplace=True)missing.plot.bar()

數(shù)據(jù)分析:帶你零基礎(chǔ)入門數(shù)據(jù)挖掘(附代碼)(數(shù)據(jù)挖掘入門教程)

# 可視化缺省值msno.matrix(Train_data.sample(250))msno.bar(Train_data.sample(1000))msno.matrix(Test_data.sample(250))msno.bar(Test_data.sample(1000))

數(shù)據(jù)分析:帶你零基礎(chǔ)入門數(shù)據(jù)挖掘(附代碼)(數(shù)據(jù)挖掘入門教程)

從上文Train_data.info()的統(tǒng)計信息可以發(fā)現(xiàn),除了notRepairedDamage 為object類型,其他都為數(shù)字。接下來將notRepairedDamage中幾個不同的值都進行顯示如下:

Train_data['notRepairedDamage'].value_counts()

數(shù)據(jù)分析:帶你零基礎(chǔ)入門數(shù)據(jù)挖掘(附代碼)(數(shù)據(jù)挖掘入門教程)

可以看出‘ – ’也為空缺值,因為很多模型對nan有直接的處理,這里我們先不做處理,先替換成nan。

Train_data['notRepairedDamage'].replace('-', np.nan, inplace=True)Train_data['notRepairedDamage'].value_counts()

Train_data.isnull().sum()

數(shù)據(jù)分析:帶你零基礎(chǔ)入門數(shù)據(jù)挖掘(附代碼)(數(shù)據(jù)挖掘入門教程)

異常值

以下兩個類別特征:嚴(yán)重傾斜,一般不會對預(yù)測有什么幫助,故這邊先刪掉,當(dāng)然你也可以繼續(xù)挖掘,但是一般意義不大

Train_data["seller"].value_counts()Train_data["offerType"].value_counts()

數(shù)據(jù)分析:帶你零基礎(chǔ)入門數(shù)據(jù)挖掘(附代碼)(數(shù)據(jù)挖掘入門教程)

del Train_data["seller"]del Train_data["offerType"]del Test_data["seller"]del Test_data["offerType"]

預(yù)測值分布

總體分布概況

數(shù)據(jù)整體服從正態(tài)分布,樣本均值和方差則相互獨立,正態(tài)分布具有很多好的性質(zhì),很多模型也假設(shè)數(shù)據(jù)服從正態(tài)分布。

例如線性回歸(linear regression),它假設(shè)誤差服從正態(tài)分布,從而每個樣本點出現(xiàn)的概率就可以表示為正態(tài)分布形式,將多個樣本點連乘再取對數(shù),就是所有訓(xùn)練集樣本出現(xiàn)的條件概率,最大化該條件概率就是LR最終求解的問題。這個條件概率的最終表達式的形式就是我們熟悉的誤差平方和。

總之, 機器學(xué)習(xí)中很多model都假設(shè)數(shù)據(jù)或參數(shù)服從正態(tài)分布。當(dāng)樣本不服從正態(tài)分布時,可以做如下轉(zhuǎn)換:

  • 線性變化z-scores
  • 使用Boxcox變換
  • 使用yeo-johnson變換

盲目假設(shè)變量服從正態(tài)分布可能導(dǎo)致不準(zhǔn)確的結(jié)果,要結(jié)合分析。例如:不能假設(shè)股票價格服從正態(tài)分布,因為價格不能為負,故我們可以將股票價格假設(shè)為服從對數(shù)正態(tài)分布,以確保其值≥0;而股票收益可能是負數(shù),因此收益可以假設(shè)服從正態(tài)分布。

當(dāng)樣本數(shù)據(jù)表明質(zhì)量特征的分布為非正態(tài)時,應(yīng)用基于正態(tài)分布的方法會作出不正確的判決。約翰遜分布族即為經(jīng)約翰(yeo-johnson)變換后服從正態(tài)分布的隨機變量的概率分布,約翰遜分布體系建立了三族分布,分別為有界SB 、對數(shù)正態(tài)SL和無界SU。

本案例的預(yù)測值為價格,顯然不符合正態(tài)分布,故分別采用無界約翰遜分布Johnson SU、正態(tài)分布normal、對數(shù)正態(tài)分布lognormal,綜合來看無界約翰遜分布對price的擬合效果更好。

y = Train_data['price']plt.figure(1); plt.title('Johnson SU')sns.distplot(y, kde=False, fit=st.johnsonsu)plt.figure(2);plt.title('Normal')sns.distplot(y, kde=False, fit=st.norm)plt.figure(3); plt.title('Log Normal')sns.distplot(y, kde=False, fit=st.lognorm)

數(shù)據(jù)分析:帶你零基礎(chǔ)入門數(shù)據(jù)挖掘(附代碼)(數(shù)據(jù)挖掘入門教程)

偏度和峰度

數(shù)據(jù)分析:帶你零基礎(chǔ)入門數(shù)據(jù)挖掘(附代碼)(數(shù)據(jù)挖掘入門教程)數(shù)據(jù)分析:帶你零基礎(chǔ)入門數(shù)據(jù)挖掘(附代碼)(數(shù)據(jù)挖掘入門教程)

sns.distplot(Train_data['price']);print("Skewness: %f" % Train_data['price'].skew())print("Kurtosis: %f" % Train_data['price'].kurt())sns.distplot(Train_data.skew(),color='blue',axlabel ='Skewness')sns.distplot(Train_data.kurt(),color='orange',axlabel ='Kurtness')Train_data.skew(), Train_data.kurt()

預(yù)測值頻數(shù)

大于20000的值很少,其實該處可將其當(dāng)作異常值處理填充或刪除,本文中經(jīng)過log變換之后,分布較均勻,可據(jù)此進行預(yù)測,這也是預(yù)測問題常用的技巧

plt.hist(Train_data['price'], orientation = 'vertical',histtype = 'bar', color ='red')plt.show()plt.hist(np.log(Train_data['price']), orientation = 'vertical',histtype = 'bar', color ='red')plt.show()

數(shù)據(jù)分析:帶你零基礎(chǔ)入門數(shù)據(jù)挖掘(附代碼)(數(shù)據(jù)挖掘入門教程)

特征分析

數(shù)字特征

‘seller’和‘offerType’已被刪除,其他特征均經(jīng)過了label coding。若需要處理的數(shù)據(jù)未label coding,則可通過如下代碼對特征進行區(qū)分:

# 數(shù)字特征numeric_features = Train_data.select_dtypes(include=[np.number])numeric_features.columns# 類型特征categorical_features = Train_data.select_dtypes(include=[np.object])categorical_features.columns

本文數(shù)據(jù)已經(jīng)label coding,故采用人工區(qū)分方法:

numeric_features = ['power', 'kilometer', 'v_0', 'v_1', 'v_2', 'v_3', 'v_4', 'v_5', 'v_6', 'v_7', 'v_8', 'v_9', 'v_10', 'v_11', 'v_12', 'v_13','v_14' ]categorical_features = ['name', 'model', 'brand', 'bodyType', 'fuelType', 'gearbox', 'notRepairedDamage', 'regionCode']

總覽

numeric_features.append('price')print(numeric_features)

數(shù)據(jù)分析:帶你零基礎(chǔ)入門數(shù)據(jù)挖掘(附代碼)(數(shù)據(jù)挖掘入門教程)

相關(guān)性分析

price_numeric = Train_data[numeric_features]correlation = price_numeric.corr()print(correlation['price'].sort_values(ascending=False),'n')f, ax = plt.subplots(figsize = (7, 7))plt.title('Correlation of Numeric Features with Price',y=1,size=16)sns.heatmap(correlation,square = True, vmax=0.8)del price_numeric['price']

數(shù)據(jù)分析:帶你零基礎(chǔ)入門數(shù)據(jù)挖掘(附代碼)(數(shù)據(jù)挖掘入門教程)

特征偏度和峰值

for col in numeric_features: print('{:15}'.format(col), 'Skewness: {:05.2f}'.format(Train_data[col].skew()) , ' ' , 'Kurtosis: {:06.2f}'.format(Train_data[col].kurt()) )

數(shù)據(jù)分析:帶你零基礎(chǔ)入門數(shù)據(jù)挖掘(附代碼)(數(shù)據(jù)挖掘入門教程)

每個數(shù)字特征的分布可視化

pd.melt():處理數(shù)據(jù),透視表格,可將寬數(shù)據(jù)轉(zhuǎn)化為長數(shù)據(jù),以便于后續(xù)分析。形成的數(shù)據(jù)即為,鍵:各特征名稱,值:特征對應(yīng)的值

sns.FacetGrid() :先sns.FacetGrid()畫出輪廓,再map()填充內(nèi)容

f = pd.melt(Train_data, value_vars=numeric_features)g = sns.FacetGrid(f, col="variable", col_wrap=2, sharex=False, sharey=False)g = g.map(sns.distplot, "value")

匿名特征分布情況

sns.pairplot():展示變量兩兩之間的關(guān)系(線性或非線性,有無較為明顯的相關(guān)關(guān)系):

  • 對角線:各個屬性的直方圖,用diag_kind屬性控制圖類型,可選"scatter"與"reg"
  • 非對角線:兩個不同屬性之間的相關(guān)圖,用kind屬性控制圖類型,可選"scatter"與"reg"
  • hue :針對某一字段進行分類

sns.set()columns = ['price', 'v_12', 'v_8' , 'v_0', 'power', 'v_5', 'v_2', 'v_6', 'v_1', 'v_14']sns.pairplot(Train_data[columns],size = 2 ,kind ='scatter',diag_kind='kde')plt.show()

數(shù)據(jù)分析:帶你零基礎(chǔ)入門數(shù)據(jù)挖掘(附代碼)(數(shù)據(jù)挖掘入門教程)

多變量與price的回歸關(guān)系

fig, ((ax1, ax2), (ax3, ax4), (ax5, ax6), (ax7, ax8), (ax9, ax10)) = plt.subplots(nrows=5, ncols=2, figsize=(24, 20))# ['v_12', 'v_8' , 'v_0', 'power', 'v_5', 'v_2', 'v_6', 'v_1', 'v_14']v_12_scatter_plot = pd.concat([Y_train,Train_data['v_12']],axis = 1)sns.regplot(x='v_12',y = 'price', data = v_12_scatter_plot,scatter= True, fit_reg=True, ax=ax1)v_8_scatter_plot = pd.concat([Y_train,Train_data['v_8']],axis = 1)sns.regplot(x='v_8',y = 'price',data = v_8_scatter_plot,scatter= True, fit_reg=True, ax=ax2)v_0_scatter_plot = pd.concat([Y_train,Train_data['v_0']],axis = 1)sns.regplot(x='v_0',y = 'price',data = v_0_scatter_plot,scatter= True, fit_reg=True, ax=ax3)power_scatter_plot = pd.concat([Y_train,Train_data['power']],axis = 1)sns.regplot(x='power',y = 'price',data = power_scatter_plot,scatter= True, fit_reg=True, ax=ax4)v_5_scatter_plot = pd.concat([Y_train,Train_data['v_5']],axis = 1)sns.regplot(x='v_5',y = 'price',data = v_5_scatter_plot,scatter= True, fit_reg=True, ax=ax5)v_2_scatter_plot = pd.concat([Y_train,Train_data['v_2']],axis = 1)sns.regplot(x='v_2',y = 'price',data = v_2_scatter_plot,scatter= True, fit_reg=True, ax=ax6)v_6_scatter_plot = pd.concat([Y_train,Train_data['v_6']],axis = 1)sns.regplot(x='v_6',y = 'price',data = v_6_scatter_plot,scatter= True, fit_reg=True, ax=ax7)v_1_scatter_plot = pd.concat([Y_train,Train_data['v_1']],axis = 1)sns.regplot(x='v_1',y = 'price',data = v_1_scatter_plot,scatter= True, fit_reg=True, ax=ax8)v_14_scatter_plot = pd.concat([Y_train,Train_data['v_14']],axis = 1)sns.regplot(x='v_14',y = 'price',data = v_14_scatter_plot,scatter= True, fit_reg=True, ax=ax9)v_13_scatter_plot = pd.concat([Y_train,Train_data['v_13']],axis = 1)sns.regplot(x='v_13',y = 'price',data = v_13_scatter_plot,scatter= True, fit_reg=True, ax=ax10)

數(shù)據(jù)分析:帶你零基礎(chǔ)入門數(shù)據(jù)挖掘(附代碼)(數(shù)據(jù)挖掘入門教程)

類別特征

查看nunique分布

for cat_fea in categorical_features: print(cat_fea '特征分布如下:') print('{}特征有{}個不同的值'.format(cat_fea, Train_data[cat_fea].nunique())) print(Train_data[cat_fea].value_counts())br

查看箱型圖

  • 直觀識別數(shù)據(jù)中的離群點
  • 直觀判斷數(shù)據(jù)離散分布情況,了解數(shù)據(jù)分布狀態(tài)

categorical_features =['model','brand','bodyType','fuelType','gearbox','notRepairedDamage']for c in categorical_features: Train_data[c] = Train_data[c].astype('category') if Train_data[c].isnull().any(): Train_data[c] = Train_data[c].cat.add_categories(['MISSING']) Train_data[c] = Train_data[c].fillna('MISSING')def boxplot(x, y, **kwargs): sns.boxplot(x=x, y=y) x=plt.xticks(rotation=90)f = pd.melt(Train_data, id_vars=['price'], value_vars=categorical_features)g = sns.FacetGrid(f, col="variable", col_wrap=2, sharex=False, sharey=False, size=5)g = g.map(boxplot, "value", "price")

數(shù)據(jù)分析:帶你零基礎(chǔ)入門數(shù)據(jù)挖掘(附代碼)(數(shù)據(jù)挖掘入門教程)

查看小提琴圖

  • 用于顯示數(shù)據(jù)分布及概率密度
  • 這種圖表結(jié)合了箱形圖和密度圖的特征,主要用來顯示數(shù)據(jù)的分布形狀

數(shù)據(jù)分析:帶你零基礎(chǔ)入門數(shù)據(jù)挖掘(附代碼)(數(shù)據(jù)挖掘入門教程)

catg_list = categorical_featurestarget = 'icu_los'for catg in catg_list : sns.violinplot(x=catg, y=target, data=Train_data) plt.show()

查看柱形圖

def bar_plot(x, y, **kwargs): sns.barplot(x=x, y=y) x=plt.xticks(rotation=90)f = pd.melt(Train_data, id_vars=['price'], value_vars=categorical_features)g = sns.FacetGrid(f, col="variable", col_wrap=2, sharex=False, sharey=False, size=5)g = g.map(bar_plot, "value", "price")

數(shù)據(jù)分析:帶你零基礎(chǔ)入門數(shù)據(jù)挖掘(附代碼)(數(shù)據(jù)挖掘入門教程)

類別頻數(shù)可視化

def count_plot(x, **kwargs): sns.countplot(x=x) x=plt.xticks(rotation=90)f = pd.melt(Train_data, value_vars=categorical_features)g = sns.FacetGrid(f, col="variable", col_wrap=2, sharex=False, sharey=False, size=5)g = g.map(count_plot, "value")

生成數(shù)據(jù)報告

用pandas_profiling生成一個較為全面的可視化和數(shù)據(jù)報告(較為簡單、方便) 最終打開html文件即可

import pandas_profilingpfr = pandas_profiling.ProfileReport(Train_data)pfr.to_file("./example.html")

編輯:王菁

校對:王欣

—完—

關(guān)注清華-青島數(shù)據(jù)科學(xué)研究院官方微信公眾平臺“ AI數(shù)據(jù)派 ”及姊妹號“ 數(shù)據(jù)派THU ”獲取更多講座福利及優(yōu)質(zhì)內(nèi)容。

相關(guān)新聞

聯(lián)系我們
聯(lián)系我們
公眾號
公眾號
在線咨詢
分享本頁
返回頂部