用Python進(jìn)行數(shù)據(jù)挖掘(數(shù)據(jù)預(yù)處理)2018-04-22

轉(zhuǎn)自:https://blog.csdn.net/u011094454/article/details/77618604
本博客進(jìn)行數(shù)據(jù)預(yù)處理的方法總結(jié)自kaggle的幾道題目:
1.HousePrices
2.Titanic
以及比較不錯(cuò)的幾個(gè)kernels:
1.https://www.kaggle.com/pmarcelino/house-prices-advanced-regression-techniques/comprehensive-data-exploration-with-python/run/1432348
2.https://www.kaggle.com/sinakhorami/titanic-best-working-classifier
3.https://www.kaggle.com/apapiu/regularized-linear-models
4.https://www.kaggle.com/serigne/stacked-regressions-top-4-on-leaderboard
本博客只能稍微了解下數(shù)據(jù)預(yù)處理,入門(mén)都算不上,真正想要深入學(xué)習(xí)特征工程建議應(yīng)該先刷完sklearn的數(shù)據(jù)預(yù)處理API文檔:
http://scikit-learn.org/stable/modules/preprocessing.html#preprocessing

  • 數(shù)據(jù)加載與粗略查看
  • 處理丟失的數(shù)據(jù)
  • 處理偏離值
  • 數(shù)據(jù)統(tǒng)計(jì)
  • 特征值的合并、連接
  • 數(shù)據(jù)轉(zhuǎn)換、標(biāo)準(zhǔn)化、歸一化

數(shù)據(jù)加載與粗略查看

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

一般訓(xùn)練與測(cè)試的數(shù)據(jù)都提供csv格式,使用pandas庫(kù)讀?。?/p>

df_train = pd.read_csv('../train.csv')

此時(shí)讀取的df_train為DataFrame格式。
同時(shí)pandas還可以讀取各種不同格式的數(shù)據(jù),如存儲(chǔ)比較快的hdf格式、excel等

但有時(shí)數(shù)據(jù)不是簡(jiǎn)單的csv,它按照文本保存,如“ID||texttexttexttext”這樣的一條數(shù)據(jù)需要將中間的“||”當(dāng)作分隔符,讀取方式如下:

train = pd.read_csv('../input/training_text', sep="\|\|", engine='python', header=None, skiprows=1, names=["ID","Text"])

更多參數(shù)應(yīng)該查閱pandas文檔。

數(shù)據(jù)粗略查看

在pandas讀進(jìn)來(lái)數(shù)據(jù)一個(gè)train后,train的格式為DataFrame,調(diào)用下面的幾個(gè)方法就可以大致了解我們得到的數(shù)據(jù)是什么,有什么特征值,特征值的數(shù)據(jù)類型是什么,如果是數(shù)值那么最大最小值是什么等:

train.head(5)     #顯示前5行數(shù)據(jù)
train.tail(5)     #顯示后5行
train.columns    #查看列名
train.info()     #查看各字段的信息
train.shape      #查看數(shù)據(jù)集行列分布,幾行幾列
train.describe() #查看數(shù)據(jù)的大體情況

如train.describe():


train.describe()

處理丟失的數(shù)據(jù)

處理這些數(shù)據(jù)以前不建議把train與test 連接起來(lái),因?yàn)檫@樣容易造成test里數(shù)據(jù)的丟失,個(gè)人認(rèn)為較好的方式為:

full_data = [train, test]

將兩個(gè)數(shù)據(jù)集合成為list,然后清洗時(shí)對(duì)其for循環(huán)即可,如:

for dataset in full_data:
    dataset['FamilySize'] = dataset['SibSp'] + dataset['Parch'] + 1

下面只介紹對(duì)測(cè)試集train 的操作。

找到丟失的位置

輸出每個(gè)列丟失值也即值為NaN的數(shù)據(jù)和,并從多到少排序:

total = train.isnull().sum().sort_values(ascending=False)
print(total)
Cabin          687
Age            177
Embarked         2
Fare             0
Ticket           0
Parch            0
SibSp            0
Sex              0
Name             0
Pclass           0
Survived         0
PassengerId      0

也可以輸出百分比:

percent =(train.isnull().sum()/train.isnull().count()).sort_values(ascending=False)
missing_data = pd.concat([total, percent], axis=1, keys=['Total', 'Percent'])
missing_data.head(20)
這里寫(xiě)圖片描述

由此可以看到‘Cabin’的缺失數(shù)量最多,‘Embarked’最少。

缺失值得處理

對(duì)缺失數(shù)據(jù)的處理我們有很多方法,如《機(jī)器學(xué)習(xí)實(shí)戰(zhàn)》里提到:

  1. 使用可用特征的均值來(lái)填補(bǔ)缺失值;
  2. 使用特殊值來(lái)填補(bǔ)缺失值,如-1;
  3. 忽略有缺失值的樣本;
  4. 使用相似樣本的均值添補(bǔ)缺失值;
  5. 使用另外的機(jī)器學(xué)習(xí)算法預(yù)測(cè)缺失值。

填補(bǔ)

#使用出現(xiàn)次數(shù)最多的值填補(bǔ)
train['Embarked'] = train['Embarked'].fillna('S')
train.product_type[train.product_type.isnull()]=train.product_type.dropna().mode().values

這里的特殊值是在這個(gè)特征下出現(xiàn)最多的一個(gè)值,特殊值的選取需要根據(jù)情況來(lái)判斷,中位數(shù)也是特殊值:

#使用中位數(shù)填補(bǔ)
train['Fare'] = train['Fare'].fillna(train['Fare'].median())
使用平均數(shù)填補(bǔ)
train['Age'] = train['Age'].fillna(train['Age'].mean())
train['LotFrontage'].fillna(train['LotFrontage'].mean())

忽略

根據(jù)情況可以選擇忽略這一特征的列和忽略出現(xiàn)缺失的那幾行。
通常后者出現(xiàn)在缺失的行數(shù)比較少的情況下。

#去掉一列
train = train.drop(['Cabin'], axis = 1)
#去掉這個(gè)特征為空的行
#當(dāng)然后面可以加上inplace=True表示直接就在內(nèi)存中替換了不用再賦值個(gè)train_new,但是本人多次刪除掉幾個(gè)行,發(fā)現(xiàn)有問(wèn)題時(shí)又需要重新建立已經(jīng)分析好的train,很浪費(fèi)時(shí)間,個(gè)人認(rèn)為還是重新開(kāi)辟一個(gè)比較好
train_new = train.drop(train[train['Embarked'].isnull()].index)
#返回已經(jīng)去掉重復(fù)行的數(shù)據(jù)集
train.drop_duplicates()

處理偏離值

查找偏離值

將數(shù)據(jù)可視化(python中的pyplot),觀察異常值,引用HousePrice中的一個(gè)例子:

#bivariate analysis saleprice/grlivarea
var = 'GrLivArea'
data = pd.concat([df_train['SalePrice'], df_train[var]], axis=1)
data.plot.scatter(x=var, y='SalePrice', ylim=(0,800000));
這里寫(xiě)圖片描述

可以發(fā)現(xiàn),有四個(gè)點(diǎn)在非常偏離的位置,先討論上面兩個(gè)偏移位。
在下方無(wú)數(shù)點(diǎn)形成非常好的線性關(guān)系,那這偏移很大的兩點(diǎn)是異常值嗎?不是,雖然偏離位置很遠(yuǎn),但是與下面無(wú)數(shù)點(diǎn)形成的線性關(guān)系還是擬合的。
再看看右下兩個(gè)值,顯然它們偏離得沒(méi)有道理,刪!

刪除偏離值

train.sort_values(by = 'GrLivArea', ascending = False)[:2]
train= train.drop(train[train['Id'] == 1299].index)
train= train.drop(train[train['Id'] == 524].index)

保留偏離值

當(dāng)然并不是所有的偏離值都需要?jiǎng)h除,具體需要在分析之后選擇處理方式。這里將偏離值保留下來(lái)并不是原封不動(dòng)保留,而需要做標(biāo)準(zhǔn)化或歸一化處理,具體的處理方式可查看最后一節(jié)數(shù)據(jù)轉(zhuǎn)換、標(biāo)準(zhǔn)化、歸一化。

數(shù)據(jù)統(tǒng)計(jì)

現(xiàn)在我們已經(jīng)拿到了一份比較完整的數(shù)據(jù),讓我們開(kāi)始對(duì)它做一個(gè)簡(jiǎn)單的統(tǒng)計(jì)。
統(tǒng)計(jì)包括數(shù)據(jù)的偏斜度、峰度、不同特征值的相關(guān)系數(shù)、協(xié)方差、均值等。

#統(tǒng)計(jì)某一列中各個(gè)元素值出現(xiàn)的次數(shù)
train['MSSubClass'].value_counts()   
 #     
#列出數(shù)據(jù)的偏斜度
train['MSSubClass'].skew()    

#列出數(shù)據(jù)的峰度
train['MSSubClass'].kurt()   

#計(jì)算兩個(gè)列的相關(guān)度
train['LotFrontage'].corr(train['LotArea'])   

#觀察兩個(gè)列的值的二維圖
x = 'GrLivArea';y = 'SalePrice'
data = pd.concat([train[y], train[x]], axis=1)
data.plot.scatter(x=x, y=y, ylim=(0,800000));#這里800000為y的最大值

#計(jì)算所有特征值每?jī)蓚€(gè)之間的相關(guān)系數(shù),并作圖表示。
corrmat = train.corr()#得到相關(guān)系數(shù)
f,ax = plt.subplots(figsize = (12,9))
sns.heatmap(corrmat, vmax = .8, square = True)#熱點(diǎn)圖

#取出相關(guān)性最大的前十個(gè),做出熱點(diǎn)圖表示
k = 10 #number of variables for heatmap
cols = corrmat.nlargest(k, 'SalePrice')['SalePrice'].index
cm = np.corrcoef(train[cols].values.T)
sns.set(font_scale=1.25)
hm = sns.heatmap(cm, cbar=True, annot=True, square=True, fmt='.2f',     annot_kws={'size': 10}, yticklabels=cols.values,    xticklabels=cols.values)
plt.show()

熱點(diǎn)圖展示:


這里寫(xiě)圖片描述

特征值的合并、連接

在合并連接之前,我們需要了解pandas.groupby這個(gè)分組方法,因?yàn)楹芏鄷r(shí)候我們是在從幾個(gè)特征值里挖掘一些值來(lái)當(dāng)作新的特征值,這樣子我們這個(gè)分組的方法就顯得尤為重要了,如按照同一個(gè)用戶進(jìn)行分組來(lái)計(jì)算這個(gè)用戶的行為次數(shù)當(dāng)作新的特征值等等

分組的常用代碼塊

#按照用戶分組---------------------一個(gè)特征值
train.groupby('userid',as_index=False)
#按照用戶與目的地分組---------------兩個(gè)特征值
train.groupby(['userid','end_loc'],as_index=False)
#用戶、起點(diǎn)、目的地-----------------三個(gè)特征值
train.groupby(['userid','start_loc','end_loc'],as_index=False)
#跟MSSubClass進(jìn)行分組,并求分組后的平均值
train[['MSSubClass', 'LotFrontage']].groupby(['MSSubClass'], as_index=False).mean()
#選取特定的屬性的某個(gè)值然后進(jìn)行分類
train[train['date']=='2017-1-2'].groupby(['userid'],as_index=False)  

按照分組的結(jié)果,得到需要的信息然后合并

#獲得分組后,統(tǒng)計(jì)分組中'end_loc'的數(shù)量返回為一列由‘userid’和‘user_count’組成的新的DataFrame
user_count = train.groupby('userid',as_index=False)['end_loc'].agg({'user_count':'count'})
#將獲得的新的DataFrame合并到train,更多的merge參數(shù)請(qǐng)查閱文檔
train= pd.merge(train,user_count,on=['userid'],how='left')

user_eloc_count = train.groupby(['userid','end_loc'],as_index=False)['userid'].agg({'user_eloc_count':'count'})
train= pd.merge(train,user_eloc_count,on=['userid','end_loc'],how='left')

數(shù)據(jù)的連接

#講訓(xùn)練數(shù)據(jù)與測(cè)試數(shù)據(jù)連接起來(lái),以便一起進(jìn)行數(shù)據(jù)清洗。
#這里需要注意的是,如果沒(méi)有后面的ignore_index=True,那么index的值在連接后的這個(gè)新數(shù)據(jù)中是不連續(xù)的,如果要按照index刪除一行數(shù)據(jù),可能會(huì)發(fā)現(xiàn)多刪一條。
merge_data=pd.concat([train,test],ignore_index=True)  

#另一種合并方式,按列名字進(jìn)行合并。
all_data = pd.concat((train.loc[:,'MSSubClass':'SaleCondition'], test.loc[:,'MSSubClass':'SaleCondition']))  

數(shù)據(jù)轉(zhuǎn)換、標(biāo)準(zhǔn)化、歸一化

數(shù)值轉(zhuǎn)換

#浮點(diǎn)型數(shù)值轉(zhuǎn)換為整型
train['Age']=train['Age'].astype(int)

#字符串的替換--映射
train['MSZoning']=train['MSZoning'].map({'RL':1,'RM':2,'RR':3,}).astype(int)
train['Embarked'] = train['Embarked'].map( {'S': 0, 'C': 1, 'Q': 2} ).astype(int)
#一般建議將map拿出來(lái)
title_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Rare": 5}
train['Title'] = train['Title'].map(title_mapping)
train['Title'] = train['Title'].fillna(0)

#將字符串特征列中的內(nèi)容分別提出來(lái)作為新的特征出現(xiàn),表現(xiàn)為0、1。
train= pd.get_dummies(houseprice)   

#將連續(xù)型特征值分塊,每一塊用數(shù)字標(biāo)識(shí)
train.loc[ train['Fare'] <= 7.91, 'Fare'] = 0
train.loc[(train['Fare'] > 7.91) & (train['Fare'] <= 14.454), 'Fare'] = 1
train.loc[(train['Fare'] > 14.454) & (train['Fare'] <= 31), 'Fare']   = 2
train.loc[ train['Fare'] > 31, 'Fare'] = 3
train['Fare'] = train['Fare'].astype(int)

下面這個(gè)數(shù)值轉(zhuǎn)換是將數(shù)值進(jìn)行l(wèi)og計(jì)算,使分布的數(shù)值顯常態(tài)

train['SalePrice'] = np.log(train['SalePrice'])

而有時(shí)這樣的log不可行,就需要使用log(x+1)來(lái) 處理,至于原因請(qǐng)點(diǎn)擊鏈接

train["SalePrice"] = np.log1p(train["SalePrice"])
#將偏斜度大于0.75的數(shù)值列l(wèi)og轉(zhuǎn)換,使之盡量符合正態(tài)分布。
skewed_feats = train[numeric_feats].apply(lambda x: skew(x.dropna())) #compute skewness
skewed_feats = skewed_feats[skewed_feats > 0.75]
skewed_feats = skewed_feats.index
all_data[skewed_feats] = np.log1p(all_data[skewed_feats])
這里寫(xiě)圖片描述

數(shù)據(jù)標(biāo)準(zhǔn)化和歸一化(Standardization、Normalization)

標(biāo)準(zhǔn)化歸一化概念不再贅述,實(shí)際使用時(shí)最主要的還是要了解什么時(shí)候需要標(biāo)準(zhǔn)化,什么時(shí)候用歸一化,還需要清楚當(dāng)前數(shù)據(jù)適合什么標(biāo)準(zhǔn)化方式等等。
sklearn.preprocessing 介紹的標(biāo)準(zhǔn)化方式有:
1. preprocessing.scale()、preprocessing.StandardScaler(),使數(shù)據(jù)集呈現(xiàn)標(biāo)準(zhǔn)正態(tài)分布,即mean = 0,且標(biāo)準(zhǔn)差std = 1。
2. MinMaxScaler 、MaxAbsScaler,前者使數(shù)據(jù)集分布在[0,1],后者分布在[-1,1]。這種方式通常在(1) 特征的標(biāo)準(zhǔn)差較小 (2) 可以使稀疏數(shù)據(jù)集中的0值繼續(xù)為0,這兩種情況下使用。
3. preprocessing.QuantileTransformer(),將數(shù)據(jù)映射到[0,1]之間均勻分布,會(huì)破壞原數(shù)據(jù)之間的相關(guān)特性。
4. 歸一化方式:preprocessing.normalize(),將樣本縮放成單位向量,(1)需要使用二次方程,比如點(diǎn)積或者其他核方法計(jì)算樣本對(duì)之間的相似性(2)常用于文本分類和內(nèi)容聚類的向量空間模型的基礎(chǔ)。

</article>

版權(quán)聲明:隨意轉(zhuǎn)載,不用告訴我,但鏈接到就行。 https://blog.csdn.net/u011094454/article/details/77618604

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容