目錄
缺失值處理
異常值處理
數據歸一化/標準化
數據連續屬性離散化
1、缺失值處理
- 數據缺失主要包括記錄缺失和字段信息缺失等情況,其對數據分析會有較大影響,導致結果不確定性更加顯著
- 缺失值的處理:刪除記錄 / 數據插補 / 不處理
import warnings
warnings.filterwarnings('ignore')
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy import stats
%matplotlib inline
# 判斷是否有缺失值數據 - isnull,notnull
# isnull:缺失值爲True,非缺失值爲False
# notnull:缺失值爲False,非缺失值爲True
# 創建數據
s=pd.Series([12,33,45,23,np.nan,np.nan,66,54,np.nan,99])
df = pd.DataFrame({'value1':[12,33,45,23,np.nan,np.nan,66,54,np.nan,99,190],
'value2':['a','b','c','d','e',np.nan,np.nan,'f','g',np.nan,'g']})
print(s.isnull()) # Series直接判斷是否是缺失值,返回一個Series
print(df.notnull()) # Dataframe直接判斷是否是缺失值,返回一個Series
print(df['value1'].notnull()) # 通過索引判斷
print('------')
s2 = s[s.isnull() == False]
df2 = df[df['value2'].notnull()] # 注意和 df2 = df[df['value2'].notnull()] ['value1'] 的區別
print(s2)
print(df2)
# 篩選非缺失值
0 False
1 False
2 False
3 False
4 True
5 True
6 False
7 False
8 True
9 False
dtype: bool
value1 value2
0 True True
1 True True
2 True True
3 True True
4 False True
5 False False
6 True False
7 True True
8 False True
9 True False
10 True True
0 True
1 True
2 True
3 True
4 False
5 False
6 True
7 True
8 False
9 True
10 True
Name: value1, dtype: bool
------
0 12.0
1 33.0
2 45.0
3 23.0
6 66.0
7 54.0
9 99.0
dtype: float64
value1 value2
0 12.0 a
1 33.0 b
2 45.0 c
3 23.0 d
4 NaN e
7 54.0 f
8 NaN g
10 190.0 g
s.dropna(inplace = True)
df2 = df['value1'].dropna()
print(s)
print(df2)
# drop方法:可直接用於Series,Dataframe
# 注意inplace參數,默認False → 生成新的值
0 12.0
1 33.0
2 45.0
3 23.0
6 66.0
7 54.0
9 99.0
dtype: float64
0 12.0
1 33.0
2 45.0
3 23.0
6 66.0
7 54.0
9 99.0
10 190.0
Name: value1, dtype: float64
# 填充/替換缺失數據 - fillna、replace
s.fillna(0,inplace=True)
print(s)
print('------')
#s.fillna(value=None,method=None,inplace=False,limit=None,downcast=None,**kwargs)
# value:填充值
# 注意inplace參數
df['value1'].fillna(method='pad',inplace=True)
print(df)
print('-----')
# method參數:
# pad / ffill → 用之前的數據填充
# backfill / bfill → 用之後的數據填充
s = pd.Series([1,1,1,1,2,2,2,3,4,5,np.nan,np.nan,66,54,np.nan,99])
s.replace(np.nan,'缺失數據',inplace = True)
print(s)
print('------')
# df.replace(to_replace=None, value=None, inplace=False, limit=None, regex=False, method='pad', axis=None)
# to_replace → 被替換的值
# value → 替換值
s.replace([1,2,3],np.nan,inplace = True)
print(s)
# 多值用np.nan代替
0 12.0
1 33.0
2 45.0
3 23.0
4 0.0
5 0.0
6 66.0
7 54.0
8 0.0
9 99.0
dtype: float64
------
value1 value2
0 12.0 a
1 33.0 b
2 45.0 c
3 23.0 d
4 23.0 e
5 23.0 NaN
6 66.0 NaN
7 54.0 f
8 54.0 g
9 99.0 NaN
10 190.0 g
------
0 1
1 1
2 1
3 1
4 2
5 2
6 2
7 3
8 4
9 5
10 缺失數據
11 缺失數據
12 66
13 54
14 缺失數據
15 99
dtype: object
------
0 NaN
1 NaN
2 NaN
3 NaN
4 NaN
5 NaN
6 NaN
7 NaN
8 4
9 5
10 缺失數據
11 缺失數據
12 66
13 54
14 缺失數據
15 99
dtype: object
# 缺失值插補
# 幾種思路:均值/中位數/衆數插補、臨近值插補、插值法
# (1)均值/中位數/衆數插補
s = pd.Series([1,2,3,np.nan,3,4,5,5,5,5,np.nan,np.nan,6,6,7,12,2,np.nan,3,4])
#print(s)
print('------')
# 創建數據
u=s.mean() # 均值
me=s.median() # 中位數
mod=s.mode() # 衆數
print('均值爲:%.2f, 中位數爲:%.2f' % (u,me))
print('衆數爲:', mod.tolist())
print('------')
# 分別求出均值/中位數/衆數
s.fillna(u,inplace = True)
print(s)
# 用均值填補
------
均值爲:4.56, 中位數爲:4.50
衆數爲: [5.0]
------
0 1.0000
1 2.0000
2 3.0000
3 4.5625
4 3.0000
5 4.0000
6 5.0000
7 5.0000
8 5.0000
9 5.0000
10 4.5625
11 4.5625
12 6.0000
13 6.0000
14 7.0000
15 12.0000
16 2.0000
17 4.5625
18 3.0000
19 4.0000
dtype: float64
# (2)臨近值插補
s = pd.Series([1,2,3,np.nan,3,4,5,5,5,5,np.nan,np.nan,6,6,7,12,2,np.nan,3,4])
#print(s)
print('------')
# 創建數據
s.fillna(method = 'ffill',inplace = True)
print(s)
# 用前值插補
0 1.0
1 2.0
2 3.0
3 3.0
4 3.0
5 4.0
6 5.0
7 5.0
8 5.0
9 5.0
10 5.0
11 5.0
12 6.0
13 6.0
14 7.0
15 12.0
16 2.0
17 2.0
18 3.0
19 4.0
dtype: float64
2、異常值處理
- 異常值是指樣本中的個別值,其數值明顯偏離其餘的觀測值。
- 異常值也稱離羣點,異常值的分析也稱爲離羣點的分析
- 異常值分析 → 3σ原則 / 箱型圖分析
- 異常值處理方法 → 刪除 / 修正填補
# 異常值分析
# (1)3σ原則:如果數據服從正態分佈,異常值被定義爲一組測定值中與平均值的偏差超過3倍的值 → p(|x - μ| > 3σ) ≤ 0.003
data = pd.Series(np.random.randn(10000)*100)
# 創建數據
u = data.mean() # 計算均值
std = data.std() # 計算標準差
stats.kstest(data, 'norm', (u, std))
print('均值爲:%.3f,標準差爲:%.3f' % (u,std))
print('------')
# 正態性檢驗
fig = plt.figure(figsize = (10,6))
ax1 = fig.add_subplot(2,1,1)
data.plot(kind = 'kde',grid = True,style = '-k',title = '密度曲線')
# 繪製數據密度曲線
ax2 = fig.add_subplot(2,1,2)
error = data[np.abs(data - u) > 3*std]
data_c = data[np.abs(data - u) <= 3*std]
print('異常值共%i條' % len(error))
# 篩選出異常值error、剔除異常值之後的數據data_c
plt.scatter(data_c.index,data_c,color = 'k',marker='.',alpha = 0.3)
plt.scatter(error.index,error,color = 'r',marker='.',alpha = 0.5)
plt.xlim([-10,10010])
plt.grid()
# 圖表表達
均值爲:0.840,標準差爲:99.366
------
異常值共27條
# 異常值分析
# (2)箱型圖分析
fig = plt.figure(figsize = (10,6))
ax1 = fig.add_subplot(2,1,1)
color = dict(boxes='DarkGreen', whiskers='DarkOrange', medians='DarkBlue', caps='Gray')
data.plot.box(vert=False, grid = True,color = color,ax = ax1,label = '樣本數據')
# 箱型圖看數據分佈情況
# 以內限爲界
s = data.describe()
print(s)
print('------')
# 基本統計量
q1 = s['25%']
q3 = s['75%']
iqr = q3 - q1
mi = q1 - 1.5*iqr
ma = q3 + 1.5*iqr
print('分位差爲:%.3f,下限爲:%.3f,上限爲:%.3f' % (iqr,mi,ma))
print('------')
# 計算分位差
ax2 = fig.add_subplot(2,1,2)
error = data[(data < mi) | (data > ma)]
data_c = data[(data >= mi) & (data <= ma)]
print('異常值共%i條' % len(error))
# 篩選出異常值error、剔除異常值之後的數據data_c
plt.scatter(data_c.index,data_c,color = 'k',marker='.',alpha = 0.3)
plt.scatter(error.index,error,color = 'r',marker='.',alpha = 0.5)
plt.xlim([-10,10010])
plt.grid()
# 圖表表達
count 10000.000000
mean 0.839649
std 99.366235
min -414.355391
25% -66.488390
50% 0.436588
75% 67.976189
max 354.605077
dtype: float64
------
分位差爲:134.465,下限爲:-268.185,上限爲:269.673
------
異常值共57條
3、數據歸一化/標準化
數據的標準化(normalization)是將數據按比例縮放,使之落入一個小的特定區間。 在某些比較和評價的指標處理中經常會用到,去除數據的單位限制,將其轉化爲無量綱的純數值,便於不同單位或量級的指標能夠進行比較和加權.
最典型的就是數據的歸一化處理,即將數據統一映射到[0,1]區間上
0-1標準化 / Z-score標準化
# 數據標準化
# (1)0-1標準化
# 將數據的最大最小值記錄下來,並通過Max-Min作爲基數(即Min=0,Max=1)進行數據的歸一化處理
# x = (x - Min) / (Max - Min)
df = pd.DataFrame({"value1":np.random.rand(10)*20,
'value2':np.random.rand(10)*100})
print(df.head())
print('------')
# 創建數據
def data_norm(df,*cols):
df_n = df.copy()
for col in cols:
ma = df_n[col].max()
mi = df_n[col].min()
df_n[col + '_n'] = (df_n[col] - mi) / (ma - mi)
return(df_n)
# 創建函數,標準化數據
df_n = data_norm(df,'value1','value2')
print(df_n.head())
# 標準化數據
# 數據標準化
# (2)Z-score標準化
# Z分數(z-score),是一個分數與平均數的差再除以標準差的過程 → z=(x-μ)/σ,其中x爲某一具體分數,μ爲平均數,σ爲標準差
# Z值的量代表着原始分數和母體平均值之間的距離,是以標準差爲單位計算。在原始分數低於平均值時Z則爲負數,反之則爲正數
# 數學意義:一個給定分數距離平均數多少個標準差?
df = pd.DataFrame({"value1":np.random.rand(10) * 100,
'value2':np.random.rand(10) * 100})
print(df.head())
print('------')
# 創建數據
def data_Znorm(df, *cols):
df_n = df.copy()
for col in cols:
u = df_n[col].mean()
std = df_n[col].std()
df_n[col + '_Zn'] = (df_n[col] - u) / std
return(df_n)
# 創建函數,標準化數據
df_z = data_Znorm(df,'value1','value2')
u_z = df_z['value1_Zn'].mean()
std_z = df_z['value1_Zn'].std()
print(df_z)
print('標準化後value1的均值爲:%.2f, 標準差爲:%.2f' % (u_z, std_z))
# 標準化數據
# 經過處理的數據符合標準正態分佈,即均值爲0,標準差爲1
# 什麼情況用Z-score標準化:
# 在分類、聚類算法中,需要使用距離來度量相似性的時候,Z-score表現更好
4、數據連續屬性離散化
連續屬性變換成分類屬性,即連續屬性離散化 在數值的取值範圍內設定若干個離散劃分點,將取值範圍劃分爲一些離散化的區間,最後用不同的符號或整數值代表每個子區間中的數據值
等寬法 / 等頻法
# 等寬法 → 將數據均勻劃分成n等份,每份的間距相等
# cut方法
ages=[20,22,25,27,21,23,37,31,61,45,41,32]
# 有一組人員年齡數據,希望將這些數據劃分爲“18到25”,“26到35”,“36到60”,“60以上”幾個面元
bins = [18,25,35,60,100]
cats = pd.cut(ages,bins)
print(cats)
print(type(cats))
print('-------')
# 返回的是一個特殊的Categorical對象 → 一組表示面元名稱的字符串
print(cats.codes, type(cats.codes)) # 0-3對應分組後的四個區間,用代號來註釋數據對應區間,結果爲ndarray
print(cats.categories, type(cats.categories)) # 四個區間,結果爲index
print(pd.value_counts(cats)) # 按照區間計數
print('-------')
# cut結果含有一個表示不同分類名稱的層級數組以及一個年齡數據進行標號的代號屬性
print(pd.cut(ages,[18,26,36,61,100],right=False))
print('-------')
# 通過right函數修改閉端,默認爲True
group_names=['Youth','YoungAdult','MiddleAged','Senior']
print(pd.cut(ages,bins,labels=group_names))
print('-------')
# 可以設置自己的區間名稱,用labels參數
df = pd.DataFrame({'ages':ages})
group_names=['Youth','YoungAdult','MiddleAged','Senior']
s = pd.cut(df['ages'],bins) # 也可以 pd.cut(df['ages'],5),將數據等分爲5份
df['label'] = s
cut_counts = s.value_counts(sort=False)
print(df)
print(cut_counts)
# 對一個Dataframe數據進行離散化,並計算各個區間的數據計數
plt.scatter(df.index,df['ages'],cmap = 'Reds',c = cats.codes)
plt.grid()
# 用散點圖表示,其中顏色按照codes分類
# 注意codes是來自於Categorical對象
[(18, 25], (18, 25], (18, 25], (25, 35], (18, 25], ..., (25, 35], (60, 100], (35, 60], (35, 60], (25, 35]]
Length: 12
Categories (4, interval[int64]): [(18, 25] < (25, 35] < (35, 60] < (60, 100]]
<class 'pandas.core.arrays.categorical.Categorical'>
-------
[0 0 0 1 0 0 2 1 3 2 2 1] <class 'numpy.ndarray'>
IntervalIndex([(18, 25], (25, 35], (35, 60], (60, 100]]
closed='right',
dtype='interval[int64]') <class 'pandas.core.indexes.interval.IntervalIndex'>
(18, 25] 5
(35, 60] 3
(25, 35] 3
(60, 100] 1
dtype: int64
-------
[[18, 26), [18, 26), [18, 26), [26, 36), [18, 26), ..., [26, 36), [61, 100), [36, 61), [36, 61), [26, 36)]
Length: 12
Categories (4, interval[int64]): [[18, 26) < [26, 36) < [36, 61) < [61, 100)]
-------
[Youth, Youth, Youth, YoungAdult, Youth, ..., YoungAdult, Senior, MiddleAged, MiddleAged, YoungAdult]
Length: 12
Categories (4, object): [Youth < YoungAdult < MiddleAged < Senior]
-------
ages label
0 20 (18, 25]
1 22 (18, 25]
2 25 (18, 25]
3 27 (25, 35]
4 21 (18, 25]
5 23 (18, 25]
6 37 (35, 60]
7 31 (25, 35]
8 61 (60, 100]
9 45 (35, 60]
10 41 (35, 60]
11 32 (25, 35]
(18, 25] 5
(25, 35] 3
(35, 60] 3
(60, 100] 1
Name: ages, dtype: int64
# 等頻法 → 以相同數量的記錄放進每個區間
# qcut方法
data = np.random.randn(1000)
s = pd.Series(data)
cats = pd.qcut(s,4) # 按四分位數進行切割,可以試試 pd.qcut(data,10)
print(cats.head())
print(pd.value_counts(cats))
print('------')
# qcut → 根據樣本分位數對數據進行面元劃分,得到大小基本相等的面元,但並不能保證每個面元含有相同數據個數
# 也可以設置自定義的分位數(0到1之間的數值,包含端點) → pd.qcut(data1,[0,0.1,0.5,0.9,1])
plt.scatter(s.index,s,cmap = 'Greens',c = pd.qcut(data,4).codes)
plt.xlim([0,1000])
plt.grid()
# 用散點圖表示,其中顏色按照codes分類
# 注意codes是來自於Categorical對象
0 (0.695, 3.202]
1 (-0.603, 0.0657]
2 (0.0657, 0.695]
3 (0.0657, 0.695]
4 (0.0657, 0.695]
dtype: category
Categories (4, interval[float64]): [(-3.104, -0.603] < (-0.603, 0.0657] < (0.0657, 0.695] < (0.695, 3.202]]
(0.695, 3.202] 250
(0.0657, 0.695] 250
(-0.603, 0.0657] 250
(-3.104, -0.603] 250
dtype: int64
------
5、重複值
pandas之drop_duplicates()