1. 程式人生 > >探索性資料分析與視覺化

探索性資料分析與視覺化

  世界如此大,我想去看看;資料如此豐富,怎麼能看完。
  面對未知,人類是富有探索精神的,可以不畏艱險,可以排除萬難,正是這種探索精神使得人類不斷進步不斷創造一個又一個奇蹟。對於紛繁複雜的資料世界,我們如何進行探索性分析呢?

探索性資料分析

  之前的一些模型是假定資料服從某種分佈,然後用樣本去調整假設分佈的引數,比如貝葉斯模型,GMM等。如果面臨錯綜複雜的資料,我們想去直接看到資料最原始的特點,比如,某個屬性是什麼分佈特點,某些屬性的關係,哪些因素具有最大量的資訊,某些不確定關係的研究等等。這個時候,假設模型的方法就不那麼好使了,這時候就較為考驗一個綜合能力了。
  所謂探索性資料分析,是在沒有頭緒的情況下,對資料進行的基本分析

,可以從中挖出更具有含金量的資訊,為進一步的研究指明方向。探索性資料分析相當於做了個全身體檢,重點部位重點檢查,後續發現的問題不歸其管,自己去找專家去搞定。

與視覺化的關係

  探索性的資料分析,側重於原始資料本身的展示,故此與資料視覺化具有相當緊密的聯絡,並且圖形展示更直觀且有利於發現有價值的資訊。
  視覺化能夠幫助我們搞定以下幾個問題:
  1. 瞭解資料基本特徵
  2. 發現數據潛在的模式
  3. 指導建模策略
  4. 為工程提供參考資訊和必要的更正

探索內容與實現

  雖說是探索,但也得有點目標才好,不能啥都不知道就愣頭愣腦地往上衝,那豈不是自我證明非二即傻。手段要靈活,快捷。
  Python2.7+ubuntu14.0
  我們採取一個先分後總的研究順序來探索。
  分別看看各個屬性的資料特徵

,大體分佈時什麼樣子的(即可能會服從什麼樣子的分佈),哪些值的資料最多,資料的均值方差最大最小各是多少,是否自相關等等。
  大體分佈最直觀的就是直方圖了,這個最易於實現。

import matplotlib.pyplot as plt
data1 = [2,2,2,2,3,3,3,4,4,4,4,4,4]
data2 = [2.3,2.4,3.4,2,1,3.4,2,5.6]
plt.xlabel('Smarts')
plt.ylabel('Probability')
plt.title(r'$\mathrm{Histogram\ of\ IQ:}\ \mu=100,\ \sigma=15$'
) plt.axis([1, 6, 0, 6]) # 橫縱範圍 plt.grid(True) plt.show(plt.hist(data2, bins=4, facecolor='green'))#分成四份 # plt.subplot()用來分子圖 plt.hist(data1, bins = 4, facecolor = 'green', alpha = 0.5) plt.hist(data2, bins = 4, facecolor = 'blue', alpha = 0.5) plt.show()

上面的程式碼得到的兩個圖如下:

直方圖兩個直方圖放到一個圖中

圖中的橫縱座標的名稱和標題只是為了展示如何給圖配置,而不是真實情況。
稍微進階一下,將多個圖放到同一個圖中展示(新增標題之類的操作和單個圖時是一樣的)。
import matplotlib.pyplot as plt
data1 = [2,2,2,2,3,3,3,4,4,4,4,4,4]
data2 = [2.3,2.4,3.4,2,1,3.4,2,5.6]
fig = plt.figure()
ax1 = fig.add_subplot(2, 2, 1) # 2*2 的 第一個,及左上側
ax1.hist(data1, bins=5, facecolor='green')#分成5份

ax2 = fig.add_subplot(222) # 2*2 的 第二個,及右上側
ax2.hist(data2, bins=5, facecolor='green')#分成5份

ax3 = fig.add_subplot(212) # 2*1 的 第3個, 及下側一整個
ax3.hist(data1, bins = 4, facecolor = 'green', alpha = 0.5)
ax3.hist(data2, bins = 4, facecolor = 'blue', alpha = 0.5)
plt.show()
將圖都放到一起

  而資料的均值、最大最小表現形式較好的則是箱線圖
import pandas as pd
import matplotlib.pyplot as plt
# 本地讀取資料 #
#df = pd.read_csv("your/file/direction/name.csv")
# 讀取網路資料 #
data_url = "https://raw.githubusercontent.com/alstat/Analysis-with-Programming/master/2014/Python/Numerical-Descriptions-of-the-Data/data.csv"
df = pd.read_csv(data_url)
print(type(df))
print df.head() # 頭
print df.tail() # 細節
print df.columns # 列名
print df.index # 行號
#print df.drop(df.columns[[1, 2]], axis = 1).head() # 捨棄列axis=1;捨棄行axis=0(預設)
print df.describe() # 統計特性,最大,最小,均值,方差
plt.show(df.boxplot()) # 箱線圖繪製展示
#### 或者採用 模組 seaborn #### 這個也非常好用,顏色自動搭配
import seaborn as sns
import matplotlib.pyplot as plt
plt.show(sns.boxplot(data = df))
#plt.show(sns.distplot(df.ix[:,2], rug = True, bins = 15))

上面程式碼的兩個圖如下:

pandas自帶的boxplot用pandas的資料框自帶的boxplot繪圖

seaborn的箱線圖用seaborn的boxplot繪圖

  是否自相關?對於時間序列,自相關是對某個屬性值,時間T和T+1時刻的值存線上性關係。
# 自相關係數
import numpy as np
def autocorrelation(x,lags):
# 計算lags階以內的自相關係數,返回lags個值,分別計算序列均值,標準差
# lags表示錯開的時間間隔
  n = len(x)
  x = np.array(x)
  result = [np.correlate(x[i:]-x[i:].mean(),x[:n-i]-x[:n-i].mean())[0]\
    /(x[i:].std()*x[:n-i].std()*(n-i)) \
    for i in range(1,lags+1)]
  return result

z = autocorrelation(df.ix[:, 1], 1)
print(z)
# 繪製個原始資料的散點圖 並將一階到10階的自相關係數也繪製到上面
import matplotlib.pyplot as plt
import numpy as np

def autocorrelation(x,lags):
# 計算lags階以內的自相關係數,返回lags個值,分別計算序列均值,標準差
# lags表示錯開的時間間隔
# Notice: 標題神馬的不支援中文 #
  n = len(x)
  x = np.array(x)
  result = [np.correlate(x[i:]-x[i:].mean(),x[:n-i]-x[:n-i].mean())[0]\
    /(x[i:].std()*x[:n-i].std()*(n-i)) \
    for i in range(1,lags+1)]
  return result


fig = plt.figure()

axes1 = fig.add_axes([0.1, 0.1, 0.8, 0.8]) # main axes
axes2 = fig.add_axes([0.2, 0.5, 0.4, 0.3]) # inset axes

# main figure
x1 = np.linspace(1, len(df.ix[:, 1]), len(df.ix[:, 1]))
axes1.plot(x1, df.ix[:, 1], 'r')
axes1.set_xlabel(df.columns[1])
axes1.set_ylabel('value')
axes1.set_title('main')

# insert
x2 = np.linspace(1, 10, 10)
y2 = autocorrelation(df.ix[:, 1], 10)
y2 = np.array(y2)
axes2.plot(x2, y2, 'g')
axes2.set_xlabel('jieci')
axes2.set_ylabel('ar')
axes2.set_title('autoRelation of different jieci')
plt.show()
原始資料的折線圖與10階內的自相關值

自相關與折線圖

  密度與熱度。密度表示分佈情況,可以是單個屬性,也可以是多個屬性的聯合分佈。單個屬性的密度可以用細密的直方圖(將bins值調大)展示。多個屬性可以用氣泡圖來展示,也可以用heat map來表示。(三維heat map)熱點圖圖示化了離散資料(事件或事物)的分佈及其相互關係,常常以一張具備顯著顏色差異圖片的方式呈現最終 結果,亮色一般代表事件發生頻率較高或事物分佈密度較大,暗色反之。很明顯,heat map對資料的要求就是需要有座標
#(1) 基於二維位置資訊的熱點圖 #
import seaborn as sns
plt.show(sns.jointplot(df.ix[:,1], df.ix[:,2], kind = "kde"))
#df.ix[:,1]代表所有點在X軸的位置 #
#df.ix[:,2]代表所有點在Y軸的位置 #
基於二維位置資訊的分佈圖
```
#(2) 或者藉助別人寫的一個模組
from pyheatmap.heatmap import HeatMap
http://www.open-open.com/lib/view/open1348041833834.html
但是不怎麼好使
#(3) 基於二維位置資訊+密度值 的 平面熱點圖 #
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np
side = np.linspace(-2, 2, 15)
X, Y = np.meshgrid(side, side)
# X 和 Y 聯合起來表示了網格的位置 #
# X 表示了網格中所有點的x軸值 #
print(type(X)) # narray 矩陣 #
Z = np.exp(-((X-1)**2 + Y**2))
# Z 表示了某個位置處的值 #
print(type(Z)) # Z是一個矩陣 #
plt.show(plt.pcolormesh(X, Y, Z, cmap=cm.RdBu))
# 沒有cmap時,預設是黑白的 #
基於二維位置資訊+密度值的平面熱點圖
#(4) 用 plt.pcolor 繪製效果, 跟pcolormesh效果類似 #
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np
fig, ax = plt.subplots()
p = ax.pcolor(X/(2*np.pi), Y/(2*np.pi), Z, cmap=cm.RdBu, vmin=abs(Z).min(), vmax=abs(Z).max())
cb = fig.colorbar(p, ax=ax)
plt.show()
plt.pcolor
#(5)基於密度值(高度)的 等高線圖 # 需要矩陣表示的高度 #
import matplotlib.pyplot as plt
cnt = plt.contour(Z, cmap=cm.RdBu, vmin=abs(Z).min(), vmax=abs(Z).max(), extent=[0, 1, 0, 1])
plt.show()
等高線圖
#(6) 基於二維位置資訊+密度值 的 三維熱點圖
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
# suface圖
fig = plt.figure(figsize=(14,6))
# `ax` is a 3D-aware axis instance because of the projection='3d' keyword argument to add_subplot
ax = fig.add_subplot(1, 2, 1, projection='3d')
p = ax.plot_surface(X, Y, Z, rstride=4, cstride=4, linewidth=0)
# surface_plot with color grading and color bar
ax = fig.add_subplot(1, 2, 2, projection='3d')
p = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm, linewidth=0, antialiased=False)
cb = fig.colorbar(p, shrink=0.5)
plt.show()
三維熱點圖
#(7)想將在各個平面上的投影也體現出來 #
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np

alpha = 0.7
phi_ext = 2 * np.pi * 0.5

def flux_qubit_potential(phi_m, phi_p):
    return 2 + alpha - 2 * np.cos(phi_p) * np.cos(phi_m) - alpha * np.cos(phi_ext - 2*phi_p)

fig = plt.figure(figsize=(8,6))
ax = fig.add_subplot(1,1,1, projection='3d')
phi_m = np.linspace(0, 2*np.pi, 100)
phi_p = np.linspace(0, 2*np.pi, 100)
X,Y = np.meshgrid(phi_p, phi_m)
Z = flux_qubit_potential(X, Y).T
ax.plot_surface(X, Y, Z, rstride=4, cstride=4, alpha=0.25)
cset = ax.contour(X, Y, Z, zdir='z', offset=-np.pi, cmap=cm.coolwarm)
cset = ax.contour(X, Y, Z, zdir='x', offset=-np.pi, cmap=cm.coolwarm)
cset = ax.contour(X, Y, Z, zdir='y', offset=3*np.pi, cmap=cm.coolwarm)
ax.set_xlim3d(-np.pi, 2*np.pi);
ax.set_ylim3d(0, 3*np.pi);
ax.set_zlim3d(-np.pi, 2*np.pi);
plt.show()
這裡寫圖片描述

  有人會問,空缺值怎麼辦,這就要看你自己怎麼處理了。
  有人會問,為什麼不加上歸一化的操作,沒有說不行,但我們更傾向於發現原始資料的特點,所以操作最好是原始資料來操作。
  看看哪些屬性對結果更重要一些。這裡可選的方法就多了,有統計學的方法,比如Pearson相關係數(Spearman係數等)、卡方檢驗,有資訊理論的方 ,比如資訊增益率、GainRatio等,有資料探勘的方法,比如邏輯迴歸的屬性係數、隨機森林的屬性重要性等。
#(1)Pearson線性相關係數
import numpy as np
# np.correlate 只是計算兩個向量對應位置相乘,再求和 
# 樣本協方差如下
cov = np.correlate(df.ix[:, 1] - df.ix[:, 1].mean(), df.ix[:, 2] - df.ix[:, 2].mean())/(len(df.ix[:, 1] - 1))
# 與下面的計算是一樣的 
#cov = np.dot(df.ix[:, 1] - df.ix[:, 1].mean(), df.ix[:, 2] - df.ix[:, 2].mean())/(len(df.ix[:, 1] - 1))
# 樣本方差如下
std1 = df.ix[:, 1].std()
std2 = df.ix[:, 2].std()
# 故兩個屬性的Pearson線性相關係數如下
Pearson = cov/(std1*std2)
print(Pearson)
# 相關係數的大小 與 線性相關性 的關係
#    0.8-1.0 極強相關
#    0.6-0.8 強相關
#    0.4-0.6 中等程度相關
#    0.2-0.4 弱相關
#    0.0-0.2 極弱相關或無相關

  看看某些屬性間是否也存在某些關係

# 兩個屬性之間的 散點圖 #
import matplotlib.pyplot as plt
plt.xlabel(df.columns[2])
plt.ylabel(df.columns[3])
plt.grid(True)
plt.show(plt.scatter(df.ix[:, 2], df.ix[:, 3]))
# 兩個屬性之間的 聯合分佈 # 用seaborn更方便一些 #
import matplotlib.pyplot as plt
import seaborn as sns
plt.show(sns.jointplot(df.ix[:,1], df.ix[:,2], kind = "kde"))
# 三個屬性之間的關係 展示 # 可以用上面的三維展示方法,plot_surface,如上文中的介紹,此處不再贅述。

散點圖與聯合分佈圖

散點圖聯合分佈圖
# 多個個體之間的關係,比如社交關係 的展示 #

  再簡單聚個類,不要小瞧聚類,很多時候會非常給力。當然聚類方法的選擇和聚類個數需要好好試試。聚類可以看到資料大體的特點,還可以把某些屬性跟所分的類聯絡到一起。

# python 聚類
#(1)K-Means聚類

#(2)基於密度的聚類