在某些比較和評價的指標處理中經常需要去除數據的單位限制,將其轉化為無量綱的純數值,便于不同單位或量級的指標能夠進行比較和加權。因此需要通過一定的方法進行數據標準化,將數據按比例縮放,使之落入一個小的特定區間。
一、標準化
1.0-1標準化
方法:將樣本中的最大值、最小值記錄下來,并通過max-min作為基數(即標準化后min=0、max=1)進行數據的歸一化處理。
x = (x - min)/(max-min)
df = pd.DataFrame({'value1':np.random.rand(10)*10,'value2':np.random.rand(10)*100}) def f(data,*cols):df_n = data.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_ndf_n = f(df,'value1','value2') df_n
?
2.Z-score標準化
z-score是一個數與樣本平均數的差再除以標準差的過程 → z=(x-μ)/σ,其中x為某一具體數,μ為平均數,σ為標準差,Z值的量代表著原始數與母體平均值之間的距離,是以標準差為單位計算的。在原始數低于平均值時Z為負數,反之則為正數。數學意義:一個給定的數距離平均數多少個標準差。
在分類、聚類算法中,需要使用距離來度量相似性的時候,Z-score表現更好 。
df = pd.DataFrame({'value1':np.random.rand(10)*100,'value2':np.random.rand(10)*100}) def f(data,*cols):df_n = data.copy()for col in cols:u = df_n[col].mean()std = df_n[col].std()df_n[col+'_n'] = (df_n[col] - u)/stdreturn df_ndf_n = f(df,'value1','value2') print(df_n) u_n1 = df_n['value1_n'].mean() std_n1 = df_n['value1_n'].std() u_n2 = df_n['value2_n'].mean() std_n2 = df_n['value2_n'].std() print('標準化后value1的均值為%3.f,標準差為%.3f'%(u_n1,std_n1)) print('標準化后value2的均值為%3.f,標準差為%.3f'%(u_n2,std_n2))
?
案例應用
# 八類產品的兩個指標value1,value2,其中value1權重為0.6,value2權重為0.4 # 通過0-1標準化,判斷哪個產品綜合指標狀況最好 df = pd.DataFrame({"value1":np.random.rand(10) * 30,'value2':np.random.rand(10) * 100},index = list('ABCDEFGHIJ')) #print(df.head()) #print('------') # 創建數據"def data_norm(data,*cols):df_n = data.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_ndf_n1 = data_norm(df,'value1','value2') # 進行標準化處理 df_n1['f'] = df_n1['value1_n'] * 0.6 + df_n1['value2_n'] * 0.4 df_n1.sort_values(by = 'f',inplace=True,ascending=False) df_n1['f'].plot(kind = 'line', style = '--.k', alpha = 0.8, grid = True) df_n1.head()
? ??
?
三、連續屬性離散化
連續屬性變換成分類屬性,即連續屬性離散化。
在數值的取值范圍內設定若干個離散劃分點,將取值范圍劃分為一些離散化的區間,最后用不同的符號或整數值代表每個子區間中的數據值
1.等寬法cut()
ages=[20,22,25,27,21,23,37,31,61,45,41,32] bins = [18,25,35,60,100] #按照18-25、25-35、35-60、60-100分為4個區間 age_cut = pd.cut(ages,bins) print('分組結果:',age_cut,type(age_cut)) #分組后結果,顯示每個值對應的區間 print('分組結果(代號表示):',age_cut.codes, type(age_cut.codes)) # 顯示每個值對應的區間代號,結果為ndarray;可以查看里邊的等級 print('分組區間:',age_cut.categories, type(age_cut.categories)) # 四個區間,結果為IntervalIndex print('分組統計:\n',pd.value_counts(age_cut)) # 按照分組區間計數 print('-------')# 默認為左開右閉區間,right參數設置為False表示左閉右開區間 print(pd.cut(ages,[18,26,36,61,100],right=False)) print('-------')# 通過labels參數自定義區間名稱 group_names=['Youth','YoungAdult','MiddleAged','Senior'] print(pd.cut(ages,bins,labels=group_names))


# 分組結果: [(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、group_names和age_cut.codes)
df = pd.DataFrame({'ages':ages}) 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) plt.scatter(df.index,df['ages'],c = age_cut.codes) #顏色按照codes分類 plt.grid()
?
2.等頻法qcut()
等頻法是將樣本數據按照個數平均進行分組
data = np.random.randn(1000) s = pd.Series(data) cats = pd.qcut(s,4) # 按四分位數進行切割,可以試試 pd.qcut(data,10) print(cats.head()) print(cats.value_counts())# qcut → 根據樣本分位數對數據進行面元劃分,得到大小基本相等的面元,但并不能保證每個面元含有相同數據個數 # 也可以設置自定義的分位數(0到1之間的數值,包含端點) → pd.qcut(data1,[0,0.1,0.5,0.9,1]) plt.scatter(s.index,s,s = 15 ,c = pd.qcut(data,4).codes) #用散點圖表示,其中顏色按照codes分類 plt.xlim([0,1000]) plt.grid() # 注意codes是來自于Categorical對象?


# 0 (-0.627, 0.0381] # 1 (-3.348, -0.627] # 2 (0.663, 3.403] # 3 (-3.348, -0.627] # 4 (-0.627, 0.0381] # dtype: category # Categories (4, interval[float64]): [(-3.348, -0.627] < (-0.627, 0.0381] < (0.0381, 0.663] < (0.663, 3.403]] # (0.663, 3.403] 250 # (0.0381, 0.663] 250 # (-0.627, 0.0381] 250 # (-3.348, -0.627] 250 # dtype: int64
?