轉(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():
處理丟失的數(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)
由此可以看到‘Cabin’的缺失數(shù)量最多,‘Embarked’最少。
缺失值得處理
對(duì)缺失數(shù)據(jù)的處理我們有很多方法,如《機(jī)器學(xué)習(xí)實(shí)戰(zhàn)》里提到:
- 使用可用特征的均值來(lái)填補(bǔ)缺失值;
- 使用特殊值來(lái)填補(bǔ)缺失值,如-1;
- 忽略有缺失值的樣本;
- 使用相似樣本的均值添補(bǔ)缺失值;
- 使用另外的機(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));
可以發(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)圖展示:
特征值的合并、連接
在合并連接之前,我們需要了解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])
數(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