用Python對(duì)數(shù)據(jù)進(jìn)行相關(guān)性分析
在進(jìn)行數(shù)據(jù)分析時(shí),我們所用到的數(shù)據(jù)往往都不是一維的,而這些數(shù)據(jù)在分析時(shí)難度就增加了不少,因?yàn)槲覀冃枰紤]維度之間的關(guān)系。而這些維度關(guān)系的分析就需要用一些方法來進(jìn)行衡量,相關(guān)性分析就是其中一種。本文就用python來解釋一下數(shù)據(jù)的相關(guān)性分析。
在進(jìn)行相關(guān)性分析之前需要介紹幾個(gè)概念,一是維度,二是協(xié)方差,三是相關(guān)系數(shù)。首先來看維度,以圖1為例,這是一個(gè)員工信息統(tǒng)計(jì)表,這里有n個(gè)員工,分別是員工1、員工2、......、員工n,每個(gè)員工有5個(gè)屬性,分別是身高、體重、年齡、工齡和學(xué)歷。每個(gè)員工的信息都是一個(gè)觀測(cè),也叫一個(gè)樣品,本文就統(tǒng)稱觀測(cè),每個(gè)員工的一個(gè)屬性叫一個(gè)指標(biāo),也叫變量、維度或者屬性,本文統(tǒng)稱維度。所以這個(gè)圖中就有n個(gè)觀測(cè)和5個(gè)維度。
圖1. 員工信息表
而協(xié)方差的定義就是E{ [ X - E(X) ] [ Y - E(Y) ] },記作Cov(X, Y),也就是兩個(gè)維度與各自期望之差的乘積的期望,期望在離散型數(shù)據(jù)中通常是均值,比如圖1中身高代表X,體重代表Y,E(X)就是身高的均值,E(Y)就是體重的均值,在利用二者分別和E(X)與E(Y)的差求協(xié)方差。而相關(guān)系數(shù)就是Cov(X, Y)/[σ(X)σ(Y)],記作ρXY,其中σ(X)和σ(Y)分別表示X和Y的標(biāo)準(zhǔn)差,所以相關(guān)系數(shù)就是兩個(gè)變量的協(xié)方差除以其標(biāo)準(zhǔn)差之積。類似的,假如某個(gè)觀測(cè)有p個(gè)維度,計(jì)算每個(gè)維度同所有維度之間的協(xié)方差,則會(huì)形成一個(gè)pxp的矩陣,矩陣的每個(gè)數(shù)是其相應(yīng)維度之間的協(xié)方差,這個(gè)矩陣就稱為協(xié)方差矩陣,協(xié)方差矩陣按照上面的方法再進(jìn)一步計(jì)算就可得到相關(guān)關(guān)系矩陣。
下面就以python代碼來解釋一下相關(guān)性分析。
首先是數(shù)據(jù)集,本文用的數(shù)據(jù)來自繪圖庫(kù)seaborn自帶的數(shù)據(jù),是非常著名的鳶尾花的數(shù)據(jù),獲取方式非常簡(jiǎn)單,執(zhí)行下面代碼即可。這里有一個(gè)問題要提示一下,部分人在load_dataset時(shí)會(huì)出錯(cuò),無法讀取數(shù)據(jù),是因?yàn)閕ris這個(gè)數(shù)據(jù)集不存在,這可能是因?yàn)閟eaborn版本的問題,如果遇到這種情況,可以去seaborn的GitHub數(shù)據(jù)網(wǎng)站自行下載數(shù)據(jù),網(wǎng)址是https://github.com/mwaskom/seaborn-data,把下載的數(shù)據(jù)解壓到seaborn-data文件夾即可,這個(gè)文件夾一般在seaborn安裝目錄下或者是當(dāng)前工作目錄下。
- import seaborn as sns
- data = sns.load_dataset('iris')
- df = data.iloc[:, :4] #取前四列數(shù)據(jù)
這次用到的數(shù)據(jù)集共有150行、5列,我們只用到前4列數(shù)據(jù)。數(shù)據(jù)集樣例如圖2所示。
圖2. 數(shù)據(jù)集樣例
接下來我們來進(jìn)行相關(guān)性分析。
首先來做一個(gè)比較簡(jiǎn)單的分析,即分析這個(gè)數(shù)據(jù)集中第1列和第3列的相關(guān)性,也就是sepal_length和petal_length這兩列之間的關(guān)系。這里我們可以用numpy、scipy和pandas三種方法。首先是numpy。
- import numpy as np
- X = df['sepal_length']
- Y = df['petal_length']
- result1 = np.corrcoef(X, Y)
得到的result1結(jié)果就是一個(gè)二維矩陣,如圖3所示。
圖3. result1計(jì)算結(jié)果
其中矩陣主對(duì)角線上的數(shù)值都為1(主對(duì)角線就是從左上角到右下角的那條斜線),這是因?yàn)橹鲗?duì)角線的數(shù)值都是每個(gè)觀測(cè)與自己的相關(guān)性,所以都是1,畢竟X=1X,Y=1Y,每個(gè)觀測(cè)都等于1乘以自身。而圖3中其他不為1的數(shù)字就是相關(guān)關(guān)系數(shù)值,一共有兩個(gè),這兩個(gè)值相等,因?yàn)檫@兩個(gè)值分別表示ρXY和ρYX,其值相等。同理我們可以求df中4個(gè)維度的相關(guān)關(guān)系,代碼如下,這里rowvar代表以列為維度。
- result2 = np.corrcoef(df, rowvar=False)
其結(jié)果如圖4所示。
圖4. result2計(jì)算結(jié)果
圖4是一個(gè)4x4的矩陣,共16個(gè)數(shù)據(jù),代表每個(gè)維度同其他維度的相關(guān)關(guān)系(也包括每個(gè)維度與其自身),主對(duì)角線為1,其他數(shù)字關(guān)于主對(duì)角線對(duì)稱,是一個(gè)對(duì)稱矩陣。
接下來我們用scipy進(jìn)行分析。代碼如下。
- import scipy.stats as ss
- result3 = ss.pearsonr(X, Y)
這個(gè)結(jié)果是(0.8717537758865831, 1.0386674194498099e-47),其返回的是兩個(gè)數(shù),第一個(gè)數(shù)是X和Y的相關(guān)關(guān)系數(shù)值,其值和前面numpy的計(jì)算結(jié)果相同,第二個(gè)是兩者不相關(guān)的概率,也就是我們統(tǒng)計(jì)學(xué)中常說的p值,但這個(gè)值是指不相關(guān)的概率,也就是值越小,代表越相關(guān),我們這里的數(shù)值非常小,代表二者的線性相關(guān)程度比較大。當(dāng)然如果相關(guān)關(guān)系數(shù)值為1,則p值為0。scipy中沒有計(jì)算相關(guān)矩陣的方法。
最后是pandas方法。
因?yàn)榍懊娴膁f本身就是pandas的DataFrame格式,所以我們可以直接拿來用。代碼如下。
- result4 = X.corr(Y)
- result5 = df.corr()
result4結(jié)果是0.8717537758865833,result5結(jié)果如圖5所示。這兩個(gè)結(jié)果和前面所得的結(jié)果相同。
圖5. result5計(jì)算結(jié)果
接下來是作圖。對(duì)于分析相關(guān)關(guān)系,一般有兩種常見的圖形,一種是散點(diǎn)圖,一種是熱力圖。散點(diǎn)圖中可以清晰看到各個(gè)坐標(biāo)點(diǎn)的分布及趨勢(shì),對(duì)于數(shù)據(jù)分析者而言,其可以更直觀地了解各個(gè)維度數(shù)據(jù)之間的關(guān)系,但這種方法也有缺點(diǎn),即不適合大數(shù)據(jù)量,因?yàn)閿?shù)據(jù)量太大,生成圖片速度會(huì)很慢,同時(shí)圖片太多不利于觀察;而熱力圖則更多從數(shù)值或顏色方面,來準(zhǔn)確描述各個(gè)維度的關(guān)系,其傳遞的信息較少,但比較適合大數(shù)據(jù)量。我們首先介紹一下散點(diǎn)圖。
生成散點(diǎn)圖可以用seaborn或者pandas。seaborn的代碼如下。
- sns.pairplot(df)
- sns.pairplot(df , hue ='sepal_width');
第一行代碼結(jié)果如圖6所示,是一張大圖,其中包含16個(gè)子圖,每個(gè)子圖都是每個(gè)維度和其他某個(gè)維度的相關(guān)關(guān)系圖,這其中主對(duì)角線上的圖,則是每個(gè)維度的數(shù)據(jù)分布直方圖。而第二行代碼是畫出同樣的圖形,但卻以sepal_width這個(gè)維度的數(shù)據(jù)為標(biāo)準(zhǔn),來對(duì)各個(gè)數(shù)據(jù)點(diǎn)進(jìn)行著色,其結(jié)果如圖7所示。從圖中可以看出,sepal_width這列數(shù)據(jù)共23個(gè)不同的數(shù)值,每個(gè)數(shù)值一種顏色,所以生成的圖是彩色的。
圖6. seaborn繪制的普通相關(guān)關(guān)系圖
圖7. seaborn繪制的以某列數(shù)據(jù)為基準(zhǔn)的相關(guān)關(guān)系圖
而另外一種繪圖方法是用pandas,其代碼如下。
- import pandas as pd
- pd.plotting.scatter_matrix(df, figsize=(12,12),range_padding=0.5);
結(jié)果如圖8所示,可以看到用pandas繪制的圖和seaborn的大體結(jié)果一樣,但圖片的可定制程度和精細(xì)度還是略差一些,所以一般情況下建議用seaborn。
圖8. pandas生成的相關(guān)關(guān)系圖
最后就是熱力圖。其代碼如下。
- import matplotlib.pyplot as plt
- figure, ax = plt.subplots(figsize=(12, 12))
- sns.heatmap(df.corr(), square=True, annot=True, axax=ax)
剛開始寫這段代碼時(shí)還出現(xiàn)了一個(gè)小問題,如圖9所示。圖9當(dāng)中第一行和最后一行的子圖只顯示了一部分,而其他子圖都是完整顯示,這是matplotlib的一個(gè)bug,因?yàn)閟eaborn是基于matplotlib的庫(kù),所以只要升級(jí)matplotlib就行了,剛開始筆者的matplotlib版本是3.1.1,現(xiàn)在已升級(jí)到3.2.2,這個(gè)bug已經(jīng)被修復(fù)。正常圖如圖10所示。第二行代碼中square=True表示每個(gè)子圖是否以正方形顯示,這里設(shè)置為True,annot=True則表示是否在圖中顯示每個(gè)子圖的數(shù)值,這里同樣設(shè)置為True。
圖9. 老版本matplotlib生成的熱力圖
圖10. 新版本matplotlib生成的熱力圖
本文從數(shù)據(jù)計(jì)算到可視化,介紹了用python求多維數(shù)據(jù)間的相關(guān)關(guān)系的多種方法,我們可以根據(jù)自己的需求來選擇對(duì)應(yīng)的方法。
作者簡(jiǎn)介:Mort,數(shù)據(jù)分析愛好者,擅長(zhǎng)數(shù)據(jù)可視化,比較關(guān)注機(jī)器學(xué)習(xí)領(lǐng)域,希望能和業(yè)內(nèi)朋友多學(xué)習(xí)交流。