機器學習數據預處理代碼彙總(最新更新20年3月1日)

這篇博客用一個pandas的DataFrame類型的數據爲例,字段名爲了不與任何第三方庫混淆,我們叫他 dataframe

這篇博客沒有長篇大論,就是希望能夠讓大家直接複製代碼,然後把dataframe變量改爲自己的dataframe變量後立竿見影得到預期結果。

博客大多數的用例dataframe,運行 dataframe.head() 可以看到類似這樣的樣子,它源於真實數據:

  tbi_value tsi bci bpi bdi bsi mask
0 871.38 806.73 1523 854 782 768 0
1 875.55 807.63 1516 852 787 788 0
2 874.53 817.04 1515 858 798 810 0
3 874.61 817.56 1506 873 812 841 1
4 870.45 817.39 1503 889 824 864 1
import numpy as np
import pandas as pd

目錄

1.描述性統計

1.1 數據基本信息

1.1.1 數據每個維度在計算機中的存儲信息

1.1.2 數據的均值、標準差、分位點、最小值、最大值、方差

1.1.3 線性相關係數(皮爾森相關係數)

1.1.4 協方差矩陣

1.1.5 方差、中位數、衆數

1.2 數值計算

1.2.1 本列所有值累加、累乘

2. 數據清洗

2.1 缺失值處理

2.1.1 確定值填充

2.1.2 參考當前列其他值填充

2.1.3 刪除行

2.1.4 拉格朗日插值法填充

2.2 異常值處理

2.2.1 根據確定條件篩選數據

2.2.2 根據正態分佈3∂原則異常值檢測

2.2.3 Z-score 異常值檢測

2.2.4 基於MAD的Z-score 異常值檢測

2.2.5  數據傾斜處理(偏度)

2.3 非數值類型處理

2.3.1 字符特徵離散化(one-hot編碼)

2.4 時間序列

2.4.1 數據重採樣

參考鏈接(感謝)


1.描述性統計

1.1 數據基本信息

1.1.1 數據每個維度在計算機中的存儲信息

dataframe.info()
可以看到下面這個輸出:
<class 'pandas.core.frame.DataFrame'>  # 表示是DataFrame類
RangeIndex: 1647 entries, 0 to 1646    # 行的index的值域
Data columns (total 7 columns):        # 一共有多少列
tbi_value    1647 non-null float64     # 下面是每一列的描述, 列名稱 | 多少個非空的值 | 值類型
tsi          1647 non-null float64
bci          1647 non-null int64
bpi          1647 non-null int64
bdi          1647 non-null int64
bsi          1647 non-null int64
mask         1647 non-null int32
dtypes: float64(2), int32(1), int64(4) # 這是統計每個類型的總個數
memory usage: 83.7 KB                  # 這是內存佔用,83.7k只佔了非常少

1.1.2 數據的均值、標準差、分位點、最小值、最大值、方差

dataframe.describe()

可以看到下面這個輸出:

  tbi_value tsi bci bpi bdi bsi mask
count 1647 1647 1647 1647 1647 1647 1647
mean 720.862125 645.353297 1683.73224 1022.375228 1016.361263 850.625987 0.477231
std 176.724807 129.814479 862.435869 373.262046 360.824353 220.219328 0.499633
min 328.8 391.14 161 282 295 247 0
25% 571.69 533.895 1104 727 751 694 0
50% 758.21 640.19 1544 984 966 873 0
75% 843.475 750.16 2198 1307 1204.5 989 1
max 1251.13 979.47 4329 2096 2337 1562 1

其中 mean表示平均值,std爲標準差,25%,50%,75%都是四分位點的值。

1.1.3 線性相關係數(皮爾森相關係數)

dataframe.corr()
  tbi_value tsi bci bpi bdi bsi mask
tbi_value 1 0.852856 0.763435 0.736944 0.83917 0.841345 -0.052892
tsi 0.852856 1 0.473282 0.457007 0.535706 0.696586 -0.060913
bci 0.763435 0.473282 1 0.693459 0.91269 0.633547 -0.022511
bpi 0.736944 0.457007 0.693459 1 0.887674 0.820403 -0.005235
bdi 0.83917 0.535706 0.91269 0.887674 1 0.832272 -0.019859
bsi 0.841345 0.696586 0.633547 0.820403 0.832272 1 -0.036575
mask -0.052892 -0.060913 -0.022511 -0.005235 -0.019859 -0.036575 1
max 1251.13 979.47 4329 2096 2337 1562 1

值域爲 【-1,1】,越靠近-1則是負相關,越靠近1則是正相關,越靠近0則越無關;

1.1.4 協方差矩陣

dataframe.cov()
  tbi_value tsi bci bpi bdi bsi mask
tbi_value 31231.65755 19565.75481 116358.0163 48612.2877 53511.05415 32743.63278 -4.670225
tsi 19565.75481 16851.79894 52987.08238 22144.1779 25092.58877 19913.7606 -3.950785
bci 116358.0163 52987.08238 743795.6287 223234.4268 284017.9467 120326.3567 -9.700207
bpi 48612.2877 22144.1779 223234.4268 139324.5554 119553.7344 67436.73277 -0.976263
bdi 53511.05415 25092.58877 284017.9467 119553.7344 130194.2139 66132.73362 -3.580166
bsi 32743.63278 19913.7606 120326.3567 67436.73277 66132.73362 48496.55262 -4.024317
mask -4.670225 -3.950785 -9.700207 -0.976263 -3.580166 -4.024317 0.249633
max 1251.13 979.47 4329 2096 2337 1562 1

這裏協方差:大於0,就是正相關;小於0,就是負相關;等於0,就是完全無關;

絕對值越大,表示相關性的程度也越大(關聯性越強),財務管理中有句話叫“協方差越小風險越低”,就是意味着這個變量對大局影響很小。

1.1.5 方差、中位數、衆數

 方差:

dataframe.var()

中位數:

dataframe.median()

衆數:

dataframe.mode()
  tbi_value tsi bci bpi bdi bsi mask
0 574.29 742.4 1613 727 598 899 0
1 NaN NaN 1935 NaN 1090 944 NaN

這樣的結果表示bci、bdi、bsi這兩個指標有2個衆數,而其他的都是1個衆數

1.1.6 查看一列中不同數值的個數

len(dataframe['列名'].unique())

這樣可以直接顯示dataframe這一列的不同種類的數量的個數,如果想要更詳細的信息,可以直接使用:

dataframe['列名'].unique()

1.2 數值計算

1.2.1 本列所有值累加、累乘

 累加:

dataframe.cumsum()
  tbi_value tsi bci bpi bdi bsi mask
0 871.38 806.73 1523 854 782 768 0
1 1746.93 1614.36 3039 1706 1569 1556 0
2 2621.46 2431.4 4554 2564 2367 2366 0
3 3496.07 3248.96 6060 3437 3179 3207 1
4 4366.52 4066.35 7563 4326 4003 4071 2
... .... ... ... ... ... ... ...
1642 1184476.07 1060500.7 2771523 1680054 1671110 1397796 783
1643 1185177.57 1061101.91 2771999 1680959 1671831 1398583 784
1644 1185871.16 1061700.62 2772420 1681881 1672543 1399372 785
1645 1186563.86 1062298.68 2772819 1682843 1673252 1400168 785
1646 1187259.92 1062896.88 2773107 1683852 1673947 1400981 786

看輸出的信息,大家可以看到這是一層層累加下去,第n行的值就是原始數據 第 n + (n-1) + (n-2) + ... + 1 行的值的總和。

累乘:

dataframe.cumprod()

與累加的輸出類似,但累乘數值容易爆表,最後會輸出 inf 表示已超出數據存儲範圍。

2. 數據清洗

2.1 缺失值處理

可以通過下面的代碼得到缺失值的數量:

dataframe.isnull().sum()

也可通過簡單的 .info() 來看缺失值的情況;

下面的代碼可以得到 dataframe的缺失值佔比情況:爲0就表示沒有缺失值

dataframe.isnull().sum()/len(dataframe)

缺失值在進行求和時,會被默認視爲0

2.1.1 確定值填充

使用 0 填充缺失值:

dataframe.fillna(0,inplace=True)

也經常用這一列的平均值填充:

dataframe.fillna(dataframe.mean(),inplace=True)

2.1.2 參考當前列其他值填充

dataframe.fillna(method='pad',inplace=True) #參考前面值
dataframe.fillna(method='bfill',inplace=True) #參考後面值

比如dataframe矩陣長這個樣子:

  0 1 2
0 1 NaN 2
1 9 NaN NaN
2 3 4 NaN
3 5 6 7

如果使用 dataframe.fillna(method='pad') 就可以得到:可以看到每列的缺失值都根據前面出現的值進行填充

  0 1 2
0 1 NaN 2
1 9 NaN 2
2 3 4 2
3 5 6 7

如果使用 dataframe.fillna(method='bfill') 就可以得到:同理,每列缺失值都根據它之後最先出現的值填充

  0 1 2
0 1 4 2
1 9 4 7
2 3 4 7
3 5 6 7

2.1.3 刪除行

dataframe.dropna(axis = 0,inplace=True)

這個可以直接刪除有缺失值的行。

如果把axis=1,則會刪除列,不建議這樣做,除非這個維度的缺失值非常嚴重。

如果希望整行都缺失才刪除,可以使用:

dataframe.dropna(axis=0, how='all', inplace=True)

2.1.4 拉格朗日插值法填充

使用拉格朗日插值法可以迅速填充缺失值,但是當連續缺失5個以上的數據,拉格朗日插值法會出現非常大的誤差:

def lagrange_fill(dataframe,colname,k=5):
    def ployinterp_column(s, n, k=5):
        y = s[list(range(n-k, n)) + list(range(n+1, n+1+k))] #取數
        y = y[y.notnull()] #剔除空值
        return lagrange(y.index, list(y))(n) #插值並返回插值結果
    for i,index in enumerate(dataframe[colname][dataframe[colname].isnull()==True].index):
        dataframe[colname][index] = ployinterp_column(dataframe[colname],i)# todo 返回當前數據的位置
    return dataframe

調用方法是:

df = lagrange_fill(df,'KMI')
# df爲dataframe格式的數據,'KMI'爲有缺失值的一列的名稱

2.2 異常值處理

當出現明顯不合理的值時,需要剔除掉這些異常值

2.2.1 根據確定條件篩選數據

dataframe= dataframe[ (dataframe['列名1'] < 800) & (dataframe['列名2'] > 600)]

上面的例子篩選出了 dataframe中 列名1 指標 <800 且 列名2 指標 >600 的數據

這個套路可以根據確定的條件無限篩選出想要的數據,注意每個獨立的小條件都要有括號 '( )'

2.2.2 根據正態分佈3∂原則異常值檢測

如果dataframe的某一列數據應該是呈現正態分佈的,那麼可以有如下篩選方案:

#.quantile(threshold)方法可以通過假定源數據服從正態分佈,然後計算位於95%的點的值
#當 threshold = .95時:
# 95.449974的數據在平均數左右兩個標準差的範圍內
# 99.730020%的數據在平均數左右三個標準差的範圍內
# 99.993666的數據在平均數左右三個標準差的範圍內

def std_delete(dataframe,colname,threshold=.95):
    se = dataframe[colname]
    return dataframe[se < se.quantile(threshold)]

#剔除掉指定列名中存在異常值的那一行
dataframe = std_delete(dataframe , colname='列名')

如果threshold = .95篩選條件感覺不太合適,也可以使 threshold = .97 或是 .99 ,但如果.99還不行,那麼就不能主觀的認爲是正態分佈,應該做假設檢驗了,看看是不是其他分佈。

2.2.3 Z-score 異常值檢測

zscore和3∂原則的計算思路相同,計算公式是:

其中 xi 是一個數據點,μ 是所有點 xi 的平均值,δ 是所有點 xi 的標準偏差。

def zscore_check(dataframe,colname,threshold=3):
    se = dataframe[colname]
    zscore = (se - se.mean()) / (se.std())
    return dataframe[zscore.abs() < threshold]

dataframe = zscore_check(dataframe,'列名')

threshold 一般爲 2.5 ,3.0 ,3.5

2.2.4 基於MAD的Z-score 異常值檢測

MAD爲(Mean Absolute Deviation,中位數絕對偏差),是單變量數據集中樣本差異性的統計量,比標準差更有彈性,它的計算公式是:

在維基百科中有細緻的推理過程:https://en.wikipedia.org/wiki/Median_absolute_deviation

根據推理,我們得到一個結果:MAD 約等於 0.6745*δ ,這個結論有利於編程,因此:

def zscore_mad_check(dataframe,colname,threshold=3.5):
    se = dataframe[colname]
    MAD = (se - se.median()).abs().median()
    zscore = ((se - se.median())* 0.6475 /MAD).abs()
    return dataframe[zscore < threshold]

dataframe= zscore_mad_check(dataframe,'列名')

同樣的, threshold 一般設置爲 2.5  3.0  3.5

2.2.5  數據傾斜處理(偏度)

使用下面的代碼確認數據是否傾斜:

from scipy import stats

stats.mstats.skew(dataframe['列名']).data

如果值大於1,則證明存在傾斜;值越接近於0,越趨近於平緩,如果傾斜,則使用下面的代碼處理:

dataframe['列名'] = np.log(dataframe['列名'])

也可以使用這段代碼得到偏度大於1的列名,表示這些列需要額外注意:

def check_skew(dataframe):
    skew_attention = []
    for column in dataframe.columns:
        if (dataframe[column].dtype == 'int64') or (dataframe[column].dtype == 'float64'):
            skew = stats.mstats.skew(dataframe[column]).data
            if skew >= 1:
                skew_attention.append(column)
    return skew_attention

 

2.3 非數值類型處理

2.3.1 字符特徵離散化(one-hot編碼)

比如dataframe是這個樣子:

  fc1 fc2 fc3
0 1 a 2
1 9 None NaN
2 3 b 2
3 5 a 7
4 5 c 7

現在 fc2 需要整理一下(離散化):

dataframe= pd.get_dummies(dataframe,dummy_na=True,columns=['fc2'])
  fc1 fc3 fc2_a fc2_b fc2_c fc2_nan
0 1 2 1 0 0 0
1 9 NaN 0 0 0 1
2 3 2 0 1 0 0
3 5 7 1 0 0 0
4 5 7 0 0 1 0

原本是object類型,這樣就可以很快的變成01類型加以區分,常用於有固定選項的特徵中。

如果沒有 “dummy_na = True”,dataframe中就不會有 “fc2_nan” 這一列;其他不變

也可以指定離散某一個數值型的特徵:

# temp可以得到離散化 ‘fc1’ 這個特徵的 dataframe
temp = pd.get_dummies(dataframe['fc1'],dummy_na=True)
# 把 dataframe與 temp 拼接起來並且刪除已經被離散化的 ‘fc1’ 特徵
dataframe= dataframe.join(temp).drop('fc1',axis = 1)

可以得到把 fc1 離散化的結果:

  fc2 fc3 fc1_1.0 fc1_3.0 fc1_5.0 fc1_9.0 fc1_nan
0 a 2 1 0 0 0 0
1 None NaN 0 0 0 1 0
2 b 2 0 1 0 0 0
3 a 7 0 0 1 0 0
4 c 7 0 0 1 0  

2.4 時間序列

2.4.1 數據重採樣

降採樣:將時間線壓縮

series.resample('M').sum()

這裏'M'代表將時間變爲以月份來記,之後的 .sum() 是對合並的數據的操作,也可以改爲 .mean() 求均值。

升採樣:將時間線拉長

series.resample('D').sum()

如果直接拉伸,會有很多NaN,因此升採樣一般情況下需要考慮空值的填充

空值取前面的值:

series.resample('D').ffill()

空值取後面的值:

series.resample('D').bfill()

線性填充:

ts.resample('H').interpolate()

 

參考鏈接(感謝)

pandas api:https://pandas.pydata.org/pandas-docs/stable/reference/index.html

sklearn api:https://scikit-learn.org/stable/modules/classes.html

Python數據分析之pandas統計分析:https://blog.csdn.net/A632189007/article/details/76176985

數據預處理與特徵選擇:https://blog.csdn.net/u010089444/article/details/70053104

總結:數據清洗的一些總結:https://blog.csdn.net/MrLevo520/article/details/77573757

異常值檢測方法彙總:https://segmentfault.com/a/1190000015926584

用Python做單變量數據集的異常點分析:https://my.oschina.net/taogang/blog/279402

Minitab 18 支持:https://support.minitab.com/zh-cn/minitab/18/

 

如果有 錯誤 or 補充 or 代碼解釋 or 其他需求,請留言;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章