1. 程式人生 > >Python資料探勘與機器學習_通訊信用風險評估實戰(2)——資料預處理

Python資料探勘與機器學習_通訊信用風險評估實戰(2)——資料預處理

系列目錄:

資料說明

通過對讀取資料的實踐,下面是資料集檔案對應讀取後的DataFrame說明。

資料檔案 DataFrame
DataTech_Credit_Train_Communication1.txt train_comm
DataTech_Credit_Train_User1 train_user
DataTech_公共資料_基礎資訊1 train_basic
DataTech_公共資料_通話1 train_call

重塑(reshape)和軸向旋轉(pivot)

其中train_comm有201703-201706共4個月的使用者通話資料,以”長格式(long)”或”堆疊格式(stacked)”儲存,UserI_Id

直接關聯其他DataFrame會出現一對多的情況,故需要對它進行重塑(reshape)和旋轉(pivot)運算。train_comm有4列資料:'UserI_Id', 'R3A_Stop_Days', 'R3A_Stop_Cnt', 'date',假設只有一個需要參與重塑的資料列,可利用DataFrame的pivot方法實現轉換,train_comm_pivoted = train_comm.pivot('UserI_Id', 'date', 'R3A_Stop_Days'),前兩個引數值分別用作行和列索引的列名,最後一個引數值是用於填充DataFrame的資料列的列名,假設有兩個需要參與重塑的資料列,那麼忽略最後一個引數,得到的DataFrame就會帶有層次化的列。其實,pivot只是一個快捷方式而已,用set_index建立層次化索引,再用unstack重塑可以達到同樣效果。

train_comm_pivoted = train_comm.pivot('UserI_Id', 'date')
# train_comm_pivoted = train_comm.set_index(['UserI_Id', 'date']).unstack('date')

    R3A_Stop_Days   R3A_Stop_Cnt
date    201703  201704  201705  201706  201703  201704  201705  201706
UserI_Id                                
10032318    1   1   1   1   1
1 1 1 10041348 1 1 1 1 1 1 1 1 10076180 1 1 1 1 1 1 1 1 10099716 4 4 4 4 2 2 2 1 10101115 1 1 1 1 1 1 1 1

層次化索引

但是,這樣生成的DataFrame有multiindex columns,而我們其他的DataFrame沒有,那麼怎樣合併具有不同列索引層次的DataFrame呢。假設合併的兩個DataFrame為train_usertrain_comm_pivoted,這裡提供兩種解決的方案。

一是Index to MultiIndex,add a level to the columns of train_user,

train_user.columns = pd.MultiIndex.from_product([train_user.columns, ['in']])


    UserI_Id        RISK_Flag
    in              in
0   60015357        0
1   60015359        1
2   60015362        1
3   60015365        0
4   10032318        1

二是MultiIndex to Index

train_comm_pivoted.columns = ['%s%s' % (a, '|%s' % b if b else '') for a, b in train_comm_pivoted.columns]

    R3A_Stop_Days|201703    R3A_Stop_Days|201704    R3A_Stop_Days|201705    R3A_Stop_Days|201706    R3A_Stop_Cnt|201703 R3A_Stop_Cnt|201704 R3A_Stop_Cnt|201705 R3A_Stop_Cnt|201706
UserI_Id                                
10032318    1   1   1   1   1   1   1   1
10041348    1   1   1   1   1   1   1   1
10076180    1   1   1   1   1   1   1   1
10099716    4   4   4   4   2   2   2   1
10101115    1   1   1   1   1   1   1   1

為了方便後續與其他資料集的合併,我選擇了MultiIndex to Index。

資料庫風格的DataFrame合併

應用pandas的merge函式,接下來就可以合併train_usertrain_comm_pivoted這兩個DataFrame了。

train_user_comm = pd.merge(train_user, train_comm_pivoted, how='left', left_on='UserI_Id', right_index=True, suffixes=('_user', '_comm'))

pd.merge函式的引數

引數 說明
left 參與合併的左側DataFrame
right 參與合併的右側DataFrame
how “inner”、”outer”、”left”、”right”,預設為”inner”
on 用於連線的列名,如果未指定,且其他連線鍵也未指定,則以left和right列名的交集作為連線鍵
left_on 左側DataFrame用作連線鍵的列
rigth_on 右側DataFrame用作連線鍵的列
left_index 將左側的行索引用作其連線鍵
right_index 將右側的行索引用作其連線鍵
suffixes 字串值元組,用於追加到重疊列名的末尾,預設為(‘_x’, ‘_y’)。

當然,合併資料集還可以用一些其他的方式,如pandas.concatDataFrame1.join(DataFrame2),DataFrame的join例項方法,能更為方便的實現按索引的合併,它還可用於合併多個帶有相同或相似索引的DataFrame物件,而不管它們有沒有重疊的列。這裡就引出下一個話題,將DataFrame的一個或多個列當做行索引來用,或者可能希望將行索引變成DataFrame的列。

列和行索引的轉換

DataFrame的set_index函式會將一個或多個列轉化為行索引,並建立一個新的DataFrame。

# column to index
train_user = train_user.set_index('UserI_Id')

reset_index的功能跟set_index剛好相反,層次化索引的級別會被轉移到列裡面。

# UserI_Id reset_index() to Column
train_comm_pivoted = train_comm_pivoted.reset_index()

移除重複資料

DataFrame中經常出現重複行,可以用DataFrame的duplicated方法返回一個布林型Series,表示各行是否是重複行,還有一個drop_duplicates方法,用於返回一個移除了重複行的DataFrame。這兩個方法預設會判斷全部列,我們也可以指定部分列進行重複項判斷。且,它們預設保留的是第一個出現的值組合,傳入引數take_last=True則保留最後一個。

train_basic = train_basic.drop_duplicates()

索引、選取

對DataFrame進行索引是獲取一個或者多個列。

train_user_comm_basic[['UserI_Id', 'RISK_Flag']].head()

    UserI_Id    RISK_Flag
0   60015357        0
1   60015359        1
2   60015362        1
3   60015365        0
4   10032318        1

但是,這種索引方式有幾個特殊的情況,首先通過切片或布林型陣列選取行。

train_basic_201706 = train_basic[train_basic['date'] == 201706]

為了在DataFrame行上進行標籤索引,引入索引欄位ix。它可以通過NumPy式的標記法和軸標籤從DataFrame選取行和列的子集。

train_user_comm_basic.ix[:3, ['UserI_Id', 'RISK_Flag']].head()

    UserI_Id    RISK_Flag
0   60015357        0
1   60015359        1
2   60015362        1
3   60015365        0

# 切片選取,行包括末端,列不包括???
train_user_comm_basic.ix[:3, :3].head()

    UserI_Id    RISK_Flag   R3A_Stop_Days|201703
0   60015357        0       1
1   60015359        1       4
2   60015362        1       2
3   60015365        0       1

通過本篇的資料預處理,基本可以形成原始基礎資料的一張寬表,因為給出的原始資料是脫敏的,已經做了離散化處理,如果認為寬表的特徵還不夠豐富的話,可以基於自己對業務和資料的理解衍生一些新的特徵。

附1:bug參考資料

微信公眾號「資料分析」,分享資料科學家的自我修養,既然遇見,不如一起成長。
資料分析