數據分析(3)——數據描述

  在前面的文章中介紹了平均數和數據的尺度,但僅僅經過它們來描述數據是不夠的,還須要經過更多的度量描述數據。算法

測度中心

  上一章已經介紹過測度中心(measure of center),測度中心也被稱爲數據平衡點,可以在某種程度上對數據進行歸納。dom

  測度中心雖然是描述數據的一種簡便的方法,但它存在有不少侷限性。下表是兩個籃球運動員在上個月比賽的得分:機器學習

  

  

  得分表中有意識地將得分從低到高排序。下面的代碼計算了A和B的均值和中位數:學習

1 import numpy as np
2
3 A = [7, 8, 9, 9, 10, 10, 11, 11, 12, 13]
4 B = [3, 3, 4, 6, 7, 10, 10, 10, 13, 13, 31]
5 mu_A, mu_B = np.mean(A), np.mean(B) # 均值
6 median_A, median_B = np.median(A), np.median(B) # 中位數
7 print('mu_A = {}, mu_B = {}'.format(mu_A, mu_B)) # mu_A = 10.0, mu_B = 10.0
8 print('median_A = {}, median_B = {}'.format(median_A, median_B)) # median_A = 10.0, median_B = 10.0

  均值A的描述較爲恰當,可是B就不必定了。B的離羣數據過多,這些數據將極大地影響均值。雖然中位數受離羣數據影響較小,但仍不能完整地描述B的特性,此時咱們須要尋求數據的其它指標。測試

數據的距

數據的全距

  測度中心用於量化數據的中心,數據的全距則用於量化數據的離散程度。spa

  全距的計算方式很簡單,使用數據的最大值減去最小值,僅此而已,它只是對數據離散程度極其基本的描述。3d

1 A = [7, 8, 9, 9, 10, 10, 11, 11, 12, 13]
2 B = [3, 3, 4, 6, 7, 10, 10, 10, 13, 13, 31]
3 range_A, range_B = max(A) - min(A), max(B) - min(B) # 全距
4 print('range_A = {}, range_B = {}'.format(range_A, range_B)) # range_A = 6, range_B = 28

  數據的最小值和最大值分別是全距的下界和上界,兩者間的距離就是數據的全距:code

  全距是由數據的極值計算得出的,僅僅度量了數據的寬度,而且不能指出數據是否包含了異常值,所以全距的使用場景十分有限,不少時候使用全距僅僅是由於它很簡單。orm

  全距有一些典型的使用場景:在算法分析時,雖然咱們用大O表示法表達算法在平均狀況下的效率,可是咱們對算法在最好和最差狀況的效率依然有很大的興趣;在軟件項目的任務評估時,一個重要的指標是「最壞狀況下的完成時間」,畢竟項目進度並不老是那麼使人歡欣鼓舞。如此看來,全距並非那麼一無可取。blog

四分位距

  首先要明確的是,四分位和四分衛沒有半點關係。

  既然全距很容易受異常值影響,那麼忽略異常值不就能夠了嗎?對於B球員來講,能夠忽略狀態及佳和極差的得分。如今又來了球員C,他的得分狀況:

  

    31分遠遠高出了其餘場次,所以忽略31分。如今問題產生了,B球員和C球員採用了不一樣的異常值忽略方式——B忽略了最低分,而C沒有,比較使用不一樣方式處理的數據,是數據分析的大忌。

   忽略異常值的一種較好的方式是使用四分位距。首先將數據排序,而後將數據等分爲4份:

  從分佈上看,四分位距保留了中間靠近均值的50%的數據:

  

  用統一的標準去除了兩組數據的異常值。

  下四分位數和上四分位數的計算方法和中位數相似。數據集有n個數據,對於下四分位數來講,若是n/4是整數,則下四分位數是n/4位置和n/4 + 1位置的兩個數的平均值;若是n/4不是整數,向上取整,該位置的數就是下四分位數。對於上四分位數來講,若是3n/4是整數,則下四分位數是3n/4位置和3n/4 + 1位置的兩個數的平均值;若是3n/4不是整數,向上取整,該位置的數就是下四分位數。

  球員B共有11個得分,11÷4=2.75,向上取整,下四分位數是數據集中的第3個,下四分位數是4;用11×3÷4=8.25,向上取整,上四分位數是數據集中的第9個,下四分位數是13。該球員的四分距是13 – 4 = 9。

1 A = [7, 8, 9, 9, 10, 10, 11, 11, 12, 13]
2 B = [3, 3, 4, 6, 7, 10, 10, 10, 13, 13, 31]
3 lower_A = np.quantile(A, 1/4, interpolation='lower')  # 下四分位數
4 higher_A = np.quantile(A, 3/4, interpolation='higher')  # 上四分位數
5 lower_B = np.quantile(B, 1/4, interpolation='lower')
6 higher_B = np.quantile(B, 3/4, interpolation='higher')
7 print('lower_A = {}, higher_A = {}'.format(lower_A, higher_A)) # lower_A = 9, higher_A = 11
8 print('lower_B = {}, higher_B = {}'.format(lower_B, higher_B)) # lower_B = 4, higher_B = 13

  固然,你也能夠把數據分紅任意塊,好比分紅100塊,這對於劃分名次頗有用。假設某個學生的高考成績是600分,單從成績沒法知道好壞,但若是說這一年高考的第90個百分數是590分,則能夠知道這個考生的分數超過了90%以上的學生。

箱形圖

   咱們常常看到箱形圖:

  知道了四分位數和四分位距,就不難理解箱形圖:

  箱形圖同時顯示了數據的全距、四分距和中位數,經過箱形圖能夠了解數據的偏斜程度。

1 import matplotlib.pyplot as plt
2 plt.boxplot([A, B], labels = ['player A', 'playerB']) # 箱形圖
3 plt.show()

  

  playerB上面還有一個小圓圈,它表示異常值,B球員得31分那場比賽被斷定爲異常值,箱形圖自動將它剔除了。

   在正態分佈的假設下,μ-3σ<=x<=μ+3σ的區域包含了絕大部分數據,該區域以外的數據被認爲是異常的(更多信息可參考:https://mp.weixin.qq.com/s/DgiLzv5sOAS7JeUDk-6fLA):

  對於箱形圖來講,設lower是下四分位數,heigher是上四分位數,range是四分位距,x是某個數據樣本,則下面的的不等式判斷x是不是異常值:

  對於B球員來講:

  

  處於-9.5或26.5以外的數值是31,所以31被斷定爲異常數據。

再談標準差

  方差、均方差和協方差(機率8)中已經討論過標準差,它衡量了數據的波動程度,即量化數據點偏離均值的程度。經過下面的代碼計算兩個球員的標準差:

1 A = [7, 8, 9, 9, 10, 10, 11, 11, 12, 13]
2 B = [3, 3, 4, 6, 7, 10, 10, 10, 13, 13, 31]
3 sigma_A, sigma_B = np.std(A), np.std(B) # 標準差
4 print('σ_A = {}, σ_B = {}'.format(sigma_A, sigma_B)) # σ_A = 1.7320508075688772, σ_B = 7.49545316720865

  球員A的標準差表示A樣本數據的離散程度,能夠認爲σA近似於A中全部數據點與均值間距離的平均值。樣本越分散,遠離均值的樣本越多,標準差越大。標準差是有單位的,其單位和計算標準差的數據單位一致,A的標準差是球員的得分數。

  能夠經過柱狀圖觀察數據和標準差的關係:

 1 def add_bar(data, mu, sigma, name):
 2     '''
 3     添加柱狀圖
 4     :param data: 數據集
 5     :param mu: 均值
 6     :param sigma:  標準差
 7     :param name: 數據集名稱
 8     '''
 9     length = len(data)
10     plt.bar(left=range(length), height=data, width=0.4, color='green', label=name)
11     plt.plot((0, length), (mu, mu), 'r-', label='均值') # 均值線
12     plt.plot((0, length), (mu + sigma, mu + sigma), 'y-', label='均值+標準差') # 均值線
13     plt.plot((0, length), (mu - sigma, mu - sigma), 'b-', label='均值-標準差') # 均值線
14     plt.rcParams['font.sans-serif'] = ['SimHei']  # 用來正常顯示中文標籤
15     plt.legend(loc='upper left')
16     plt.title('bar of ' + name)
17
18 fig = plt.figure()
19 fig.add_subplot(1, 2, 1)
20 add_bar(A, mu_A, sigma_A, 'A')
21 fig.add_subplot(1, 2, 2)
22 add_bar(B, mu_B, sigma_B, 'B')
23 plt.show()

  中間紅線是均值。黃線和藍線分別表示均值加減標準差,標準差越大,黃線和藍線之間的距離也越大,說明數據的離散程度越大。在兩條線以外的數據被認爲是離羣數據。

變異測度

  測度中心和標準差均可以描述數據集的特徵,兩者都是有單位的,若是想要比較兩個不一樣的數據集,特別對不一樣尺度的數據集進行橫向比較,就須要有一種方式去掉單位。

  變異係數(coefficient of variation)是標準差和均值的比率,兩者相除去掉了單位,並對標準差進行了標準化處理,這種測度也稱爲變異測度。

  假設下表是NBA中鋒和控球后衛的身高數據:

  能夠看到,中鋒的平均身高較高,但變異係數只有2.4%,說明做爲球隊中最高大的隊員,各中鋒之間的身高差距不大。控球后衛雖然平均身高更接近普通人,但變異係數是8.0%,說明各球隊控球后衛的身高差別也較爲明顯,該位置對身高的要求相對較弱。

z分數(z-scorce)

  z分數也稱相對分數,用於描述單個數據點和均值之間的距離。數據點和z分數的計算方法是:

  x(i)表示第i個數據點,σ是樣本的標準差,帶上帽子的x是均值。

  標準差近似於全部數據點與均值間距離的平均值,z分數是單個數據點和均值間的距離,更確切地說,是標準化後單個數據點和均值間的距離。

1 z_source_A = (np.array(A) - mu_A) / sigma_A
2 z_source_B = (np.array(B) - mu_B) / sigma_B
3 print('z_source_A =', z_source_A)
4 print('z_source_B =', z_source_B)

  z_source_A = [-1.73205081 -1.15470054 -0.57735027 -0.57735027 0. 0. 0.57735027 0.57735027 1.15470054 1.73205081]

  z_source_B = [-0.9338995 -0.9338995 -0.80048529 -0.53365686 -0.40024264 0. 0. 0. 0.40024264 0.40024264 2.80169851]

   對於的z分數來講,均值的z分數是0,均值加標準差的z分數是1,均值減標準差的z分數是-1:

 1 def add_z_bar(z_source, name):
 2     ''' 添加z_source柱狀圖 '''
 3     length = len(z_source)
 4     plt.bar(left=range(length), height=z_source, width=0.4, color='green', label=name)
 5     plt.plot((0, length), (0, 0), 'r-', label='z_source of μ')
 6     plt.plot((0, length), (1, 1), 'b-', label='z_source of μ')
 7     plt.plot((0, length), (-1, -1), 'y-', label='z_source of μ')
 8
 9     plt.title('bar of ' + name)
10 fig = plt.figure()
11 # plt.subplots_adjust(wspace=0.5, hspace=0.5)
12 fig.add_subplot(2, 1, 1)
13 add_z_bar(z_source_A, 'z source of A')
14 fig.add_subplot(2, 1, 2)
15 add_z_bar(z_source_B, 'z source of B')
16 plt.show()

  低於均值的數據,z分數是負值;高於均值的數據,z分數是正值;等於z分數的數據,均值爲0。下圖能夠看出z分數和均值的關係:

相關係數

  相關係數是描述兩個變量間關聯性強弱的量化指標。數據的各個特徵之間存在關聯關係是機器學習模型的重要假設,預測可以成立的緣由正是因爲特徵間存在某種相關性。

  相關係數的值介於-1到1之間。兩個特徵間的關係越強,相關係數越接近±1;關係越若,越接近0。接近+1,表示一個指標增長了,另外一個也隨之增長;接近-1,表示一個指標增長了,另外一個指標將下降。

  成年男性的腳長約等與身高的1/7,下面的代碼生成了200個身高和腳長的正態分佈數據:

 1 import numpy as np
 2 import matplotlib.pyplot as plt
 3 import pandas as pd
 4
 5 def create_data(count=200):
 6     '''
 7     構造2維訓練集
 8     :param model: train:訓練集,  test:測試集
 9     :param count: 樣本數量
10     :return: X1:身高維度的列, X2:腳長維度的列表
11     '''
12     np.random.seed(21)  # 設置seed使每次生成的隨機數都相等
13     X1 = np.random.normal(1.7, 0.036, count)  # 生成200個符合正態分佈的身高數據
14     low, high = -0.01, 0.01
15     # 設置身高對應的腳長,正常腳長=身高/7±0.01
16     X2 = X1 / 7 + np.random.uniform(low=low, high=high, size=len(X1))
17     return X1, X2
18
19 X1, X2 = create_data()
20 df = pd.DataFrame({'height':X1, 'foot':X2})
21 print(df.head()) # 顯示前5個數據

   height foot

  0 1.698129 0.250340

  1 1.695997 0.233121

  2 1.737505 0.247780

  3 1.654757 0.238051

  4 1.726834 0.241137

  身高和腳長的維度不一樣,1釐米對於身高來講相差不大,但對於腳長來講就很大了。爲了尋找關聯關係,須要對兩個維度進行標準化處理,將兩者壓縮到統一尺度。

1 from sklearn import preprocessing
2
3 # 使用z分數標準化
4 df_scaled = pd.DataFrame(preprocessing.scale(df), columns=['height_scaled', 'foot_scaled'])
5 print(df_scaled.head())

  sklearn的preprocessing使用了z分數標準化,結果以下:

   height_scaled foot_scaled

  0 -0.051839 0.959658

  1 -0.110551 -1.389462

  2 1.032336 0.610501

  3 -1.246054 -0.716968

  4 0.738525 -0.295843

  如今能夠看看兩個維度的相關係數:

corr = df_scaled.corr() # 兩個維度的相關係數
print(corr)

   height_scaled foot_scaled

  height_scaled 1.000000 0.614949

  foot_scaled 0.614949 1.000000

  這個結果告訴咱們,身高和腳長關聯關係,因爲corr()分析的是線性相關,所以即便相關係數爲0,也不能明兩個特徵間沒有關係,只能說不存在線性關係。

  


  做者:我是8位的

  出處:https://mp.weixin.qq.com/s/ysMdUdcAk9BuXNH9bvqOBg

  本文以學習、研究和分享爲主,如需轉載,請聯繫本人,標明做者和出處,非商業用途! 

  掃描二維碼關注做者公衆號「我是8位的」

相關文章
相關標籤/搜索