您好,登錄后才能下訂單哦!
這篇文章主要介紹“Python怎樣描繪數據”,在日常操作中,相信很多人在Python怎樣描繪數據問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Python怎樣描繪數據”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
群體參數是用一些數字來表示群體的特征。我們在 統計概述中已經介紹了兩個群體參數,群體平均值和群體方差。群體平均值(population mean)反映群體總體狀況,定義如下:
μ=1N∑i=0Nxiμ=1N∑i=0Nxi
群體方差(population variance)反映群體的離散狀況,定義如下:
σ2=1N∑i=0N(xi?μ)2σ2=1N∑i=0N(xi?μ)2
方差的平方根,即σσ,稱為群體標準差(standard deviation)。從物理的角度上來看,平均值和標準差所帶的單位,都和原始數據相同。在多數統計案例中,大部分的群體數據會落在平均值加減一個標準差的范圍內。
還有一些參數要通過對群體成員進行排序才能獲得。比如群體的最大值(max)和最小值(min)。在這一類參數中,還經常會用到中位數(median)和四分位數(quartile)。對成員進行排序后,最中間成員的取值就是中位數。如果群體總數為偶數,那么中位數就是中間兩個成員取值的平均值。按照大于還是小于中位數的標準,成員可以劃分為數目相同的兩組。對這兩組再求中位數,就可以獲得下四分位數(lower quartile)和上四分位數(upper quartile)。Q1Q1和Q3Q3之間的距離,稱為四分位距(IQR,inter quartile range),也是一個常見的群體參數。我們用下面符號表示:
Q1=lower quartileQ1=lower quartile
Q2=M=medianQ2=M=median
Q3=upper quartileQ3=upper quartile
IQR=Q3?Q1IQR=Q3?Q1
中位數是按照50%劃分數據,下四分位數是按照25%劃分數據,上四分位數是按照75%劃分數據。其實,中位數和四分位數都屬于百分位數(percentile)。我們用任意比例來劃分數據,從而取得百分位數。把數據按數值大小排列,處于p%位置的成員的取值,稱第p百分位數。
我們可以計算出 湘北高中學生身高數據的描述參數:
mean: 172.075924 variance: 102.570849846 standard deviation: 10.1277267857 median: 172.21 lower percentile: 165.31 upper percentile: 178.9025 IQR: 13.5925
代碼如下:
import numpy as npwith open("xiangbei_height.txt", "r") as f: lines = f.readlines() x = list(map(float, lines))print("mean:", np.mean(x))print("variance:", np.var(x))print("standard deviation:", np.std(x))print("median:", np.median(x))print("lower percentile:", np.percentile(x, 25))print("upper percentile:", np.percentile(x, 75))print("IQR:", np.percentile(x, 75) - np.percentile(x, 25))
數據繪圖利用了人類對形狀的敏感。在通過數據繪圖,我們可以將數字轉換的幾何圖形,讓數據中的信息變得更容易消化。數據繪圖曾經是個費時費力的手工活,但計算機圖形的發展讓數據繪圖變得簡單。這兩年更是新興起“數據可視化”,用很多炫目的手段來呈現數據。但說到底,經典的繪圖只有那么幾種,如餅圖、散點圖、曲線圖。“數據可視化”中的創新手法,也只不過是從這些經典方法中衍生出來的。由于人們已經形成了約定俗成的數據繪圖習慣,繪圖方式上的過度創新甚至會誤導讀者。所以,這里出現的,也是經典的統計繪圖形式。
由于這一系列統計教程主要用Python,我將基于Matplotlib介紹幾種經典的數據繪圖方式。Matplotlib是基于numpy的一套Python工具包,提供了豐富的數據繪圖工具。當然,Matplotlib并非唯一的選擇。有的統計學家更偏愛R語言,而Web開發者流行使用D3.js。熟悉了一種繪圖工具后,總可以觸類旁通,很快地掌握其他的工具。
我們將以2011年幾個國家的GDP數據為例子,看看如何繪制經典的餅圖和條形圖。數據如下:
USA 15094025 China 11299967 India 4457784 Japan 4440376 Germany 3099080 Russia 2383402 Brazil 2293954 UK 2260803 France 2217900 Italy 1846950
這是一個只有10個成員的群體。群體成員的取值即該成員的2011年的GDP總額。這里的單位是(百萬美元)。
我們先來繪制餅圖 (pie plot)。繪制餅圖就像分披薩。整個披薩代表成員取值的總和。每個成員根據自己取值的大小,拿相應大小的那塊兒披薩。把上面的數據繪制成餅圖:
從圖中可以看到,在這場“分大餅”的游戲中,美國和中國占了大的份額。不過,人們從餅圖中讀到的只是比例,沒辦法獲得成員的具體數值。因此,餅圖適用于表示成員取值在總和中所占的百分比。上面餅圖的代碼如下:
import matplotlib.pyplot as plt# quants: GDP# labels: country namelabels = [] quants = []# Read datawith open('major_country_gdp.txt', 'r') as f: for line in f: info = line.split() labels.append(info[0]) quants.append(float(info[1]))print(quants)# make a square figureplt.figure(1, figsize=(6,6))# For China, make the piece explode a bitdef explode(label, target='China'): if label == target: return 0.1 else: return 0 expl = list(map(explode,labels))# Colors used. Recycle if not enough.colors = ["pink","coral","yellow","orange"]# Pie Plot# autopct: format of "percent" string;plt.pie(quants, explode=expl, colors=colors, labels=labels, autopct='%1.1f%%',pctdistance=0.8, shadow=True) plt.title('Top 10 GDP Countries (2011)', bbox={'facecolor':'0.8', 'pad':5}) plt.show()
餅圖的缺點是無法表達成員的具體取值,而條形圖(bar plot)正是用于呈現數據取值。條形圖繪制的是一個個豎直的長條,這個長條的高度就代表了取值。還是用上面2011年GDP的數據,用條形圖繪制出來就是:
條形圖有水平和豎直兩個方向。水平方向上標出了每個豎條對應的國家,豎直方向標出了GDP的數值。這樣,讀者就可以讀出每個國家的GDP了。上面繪圖的代碼如下:
import matplotlib.pyplot as pltimport numpy as np# quants: GDP# labels: country namelabels = [] quants = []# Read datawith open('major_country_gdp.txt') as f: for line in f: info = line.split() labels.append(info[0]) quants.append(float(info[1])) width = 0.4ind = np.linspace(0.5,9.5,10)# make a square figurefig = plt.figure(1, figsize=(12,6)) ax = fig.add_subplot(111)# Bar Plotax.bar(ind-width/2,quants,width,color='coral')# Set the ticks on x-axisax.set_xticks(ind) ax.set_xticklabels(labels)# labelsax.set_xlabel('Country') ax.set_ylabel('GDP (Million US dollar)')# titleax.set_title('Top 10 GDP Countries (2011)', bbox={'facecolor':'0.8', 'pad':5}) plt.show()
基本的條形圖就是這樣一種標記數據取值的繪圖方式。如果想知道數值,那么可以直接從數據表中讀出來,大可以不必畫條形圖。統計繪圖中更常用一種從條形圖中衍生出來的繪圖方式:直方圖(histogram)。直方圖會對群體數據進行預處理,然后再把預處理結果用條形圖的形式畫出來。舉一個簡單的例子,在繪圖中呈現 湘北高中所有學生的身高數據。想象一下,如果讓每個學生的身高對應一個豎條,那么圖上就會密密麻麻地擠滿數千個豎條,很難提供有價值的信息。但如果畫成直方圖的形式,看起來就會如下圖:
在這幅圖中,橫坐標成了身高取值。每個豎條的寬度對應了一定的身高范圍,例如170cm到172cm。豎條的高度,對應了身高在該區間內的學生數。因此,直方圖先進行了一次分組的預處理,然后用條形圖的辦法,畫出了每個組中包含的成員總數。在分組的處理中,一些原始信息丟失,以至于從豎條中沒辦法讀出學生的具體身高。但得到簡化的信息變得更容易理解。看了這個圖之后,我們可以有信心地說,大部分學生的身高在170cm附近。而身高低于150cm或者身高高于190cm的學生占據的比例很少。如果一個人只是讀原始數據,很難短時間內獲得上面的結論。
直方圖繪圖程序如下:
import numpy as npimport matplotlib.pyplot as plt with open("xiangbei_height.txt", "r") as f: lines = f.readlines() x = list(map(float, lines)) plt.title("Heights of Students (Shohoku High School)") plt.hist(x, 50) plt.xlabel("height (cm)") plt.ylabel("count") plt.show()[object Object]
代碼中的hist()函數用于繪制直方圖,其中的50說明了要生成的區間分組的個數。根據需要,你也可以具體說明在哪些區間形成分組。
趨勢圖(run chart)又稱為折線圖,經常用于呈現時間序列。時間序列是隨著時間產生的一組數據,比如上海去年每一天的氣溫,再比如中國最近50年的GDP。趨勢圖會把相鄰時間點的數據用直線連接起來,從而從視覺上體現出數據隨時間變化的特征。趨勢圖在生活中很常見,例如股民就經常會通過類似的圖來了解股價隨時間的變化。下面是 中國1960-2015年GDP的趨勢圖:
在這個趨勢圖中很容易看到,中國的GDP隨著時間快速增長。繪圖的代碼如下:
import numpy as npimport matplotlib.pyplot as plt# read datawith open("China_GDP.csv", "r") as f: lines = f.readlines() info = lines[1].split(",")# convert datax = [] y = []def convert(info_item): return float(info_item.strip('"'))for count, info_item in enumerate(info): try: y.append(convert(info_item)) x.append(1960 + count) except ValueError: print("%s is not a float" % info_item)# plotplt.title("China GDP") plt.plot(x, y) plt.xlabel("year") plt.ylabel("GDP (USD)") plt.show()
上面的繪圖方式,本質上都是二維統計圖。餅圖是國別和比例的二維信息,直方圖體現了身高和人數的二維關系,趨勢圖的兩個維度則是時間和GDP。散點圖(scatter plot)是一種最直接的表達二維關系的繪圖方式。二維繪圖的其他方式,都可以理解成散點圖的一個變種。
散點圖通過在二維平面上標記出數據點來呈現數據。如果我們想研究湘北高中學生 身高和 體重的關系,就可以在表示“身高-體重”的二維平面上,標記出所有成員的數據:
在這個散點圖中,二維平面的橫向代表身高,縱向代表體重,每一個點代表了一個學生。通過這個點對應的橫縱坐標,就可以讀出該學生的身高和體重。散點圖可以直觀地呈現所有數據,因此上可以告訴我們整體分布上有何特征。我們從圖中可以看到,體重大體上隨著身高增長而增長。
繪圖代碼如下:
import numpy as npimport matplotlib.pyplot as pltdef read_data(filename): with open(filename) as f: lines = f.readlines() return np.array(list(map(float, lines))) height = read_data("xiangbei_height.txt") weight = read_data("xiangbei_weight.txt") plt.scatter(height, weight) plt.title("Shohoku High School") plt.xlabel("height(cm)") plt.ylabel("weight(kg)") plt.ylim([20, 120]) plt.show()
散點是通過二維的位置來表示數據。在應用中,還可以通過散點的大小來表示三維的數據。這種進化了的散點圖稱為泡泡圖(bubble plot)。除了散點的大小,泡泡圖有時還會用散點的顏色來表達更高維度的信息。
我們來看泡泡圖的一個例子。下圖中繪出了亞洲主要城市的人口。城市的位置包含了二維的信息,即經度和緯度。此外,人口構成了第三維。我們用散點的大小來表示這一維度。
數據如下:
Shanghai 23019148 31.23N 121.47E China Mumbai 12478447 18.96N 72.82E India Karachi 13050000 24.86N 67.01E Pakistan Delhi 16314838 28.67N 77.21E India Manila 11855975 14.62N 120.97E Philippines Seoul 23616000 37.56N 126.99E Korea(South) Jakarta 28019545 6.18S 106.83E Indonesia Tokyo 35682460 35.67N 139.77E Japan Peking 19612368 39.91N 116.39E China
代碼中使用了matplotlib的Basemap模塊來繪制地圖:
from mpl_toolkits.basemap import Basemapimport matplotlib.pyplot as pltimport numpy as np#============================================# read datanames = [] pops = [] lats = [] lons = [] countries = [] with open("major_city.txt", "r") as f: for line in f: info = line.split() names.append(info[0]) pops.append(float(info[1])) lat = float(info[2][:-1]) if info[2][-1] == 'S': lat = -lat lats.append(lat) lon = float(info[3][:-1]) if info[3][-1] == 'W': lon = -lon + 360.0 lons.append(lon) country = info[4] countries.append(country)#============================================# set up map projection with# use low resolution coastlines.map = Basemap(projection='ortho',lat_0=35,lon_0=120,resolution='l')# draw coastlines, country boundaries, fill continents.map.drawcoastlines(linewidth=0.25) map.drawcountries(linewidth=0.25)# draw the edge of the map projection region (the projection limb)map.drawmapboundary(fill_color='#689CD2')# draw lat/lon grid lines every 30 degrees.map.drawmeridians(np.arange(0,360,30)) map.drawparallels(np.arange(-90,90,30))# Fill continent wit a different colormap.fillcontinents(color='#BF9E30',lake_color='#689CD2',zorder=0)# compute native map projection coordinates of lat/lon grid.x, y = map(lons, lats) max_pop = max(pops)# Plot each city in a loop.# Set some parameterssize_factor = 160.0y_offset = 15.0rotation = 30adjust_size = lambda k: size_factor*(k-10000000)/max_popfor i,j,k,name in zip(x,y,pops,names): cs = map.scatter(i,j,s=adjust_size(k),marker='o',color='#FF5600') plt.text(i,j+y_offset,name,rotation=rotation,fontsize=10) print(i, j) examples = [12000000, 24000000, 36000000] pop = 12000000plt.scatter(300000, 300000,s=adjust_size(pop),marker='o',color='red') plt.text(300000, 300000+y_offset,str(pop/1000000) + "million",rotation=0,fontsize=10) pop = 24000000plt.scatter(3300000, 300000,s=adjust_size(pop),marker='o',color='red') plt.text(3300000, 300000+y_offset,str(pop/1000000) + "million",rotation=0,fontsize=10) pop = 36000000plt.scatter(6300000, 300000,s=adjust_size(pop),marker='o',color='red') plt.text(6300000, 300000+y_offset,str(pop/1000000) + "million",rotation=0,fontsize=10) plt.title('Major Cities in Asia & Population') plt.show()
之前的繪圖方式側重點在原始數據。還有一些繪圖是為了呈現群體參數,比如箱形圖(box plot)。比如 湘北高中身高數據繪制成箱形圖:
如圖中標注的,箱形圖體現的主要是中位數和四分位數。上下四分位數構成了箱子,其中包含了一半的數據成員。此外,上下還有兩個邊界,位于箱子的上下邊緣各外推1.5個箱子高度的位置。如果外推1.5個箱子位置超出了數據庫的極值,那么邊界換成極值的高度。否則,將有數據點超出邊界。這些數據點被認為是異常值(outlier),用散點的方式畫出。
代碼如下:
import matplotlib.pyplot as plt with open("xiangbei_height.txt", "r") as f: lines = f.readlines() x = list(map(float, lines)) plt.boxplot(x) plt.title("box plot of Shohoku High School") plt.xticks([1], ['Shohoku']) plt.ylabel("height (cm)") plt.show()
箱形圖體現了一個思路,就是在繪制原始數據的同時畫出群體參數,從而輔助我們理解數據。比如,我們可以在直方圖中標出平均值和標準差:
代碼如下:
import numpy as npimport matplotlib.pyplot as plt with open("xiangbei_height.txt", "r") as f: lines = f.readlines() x = list(map(float, lines)) plt.title("Heights of Students (Shohoku High School)") plt.hist(x, 50) plt.xlabel("height (cm)") plt.ylabel("count") mu = np.mean(x) std = np.std(x) h = 120text_color = "white"plt.axvline(x=mu, color="red") plt.text(mu, h,'mean',rotation=90,color=text_color) plt.axvline(x=mu-std, color="coral") plt.text(mu-std, h,'mean-std',rotation=90,color=text_color) plt.axvline(x=mu+std, color="coral") plt.text(mu+std, h,'mean+std',rotation=90,color=text_color) plt.show()
盡管這里說明了一些常用的數據繪圖方法,但數據繪圖的過程中有很多人為創作的因素在。因此,同一個數據庫,甚至同一種繪圖形式,都可能產生多種多樣的數據圖像。不同的數據圖像,在傳遞信息的有效性上,會產生不小的差別。怎樣畫好數據圖呢?我根據自己的經驗,總結了下面幾個標準:
確定目的。盡管在研究過程中,我們會畫出大量的數據圖,但在展示數據圖時,要有所側重。
在標題中說明一張數據圖的主要內容。
標明每一個坐標軸,并標明坐標的刻度和單位。
如果沒有坐標軸,需要用圖例來說明讀數。例如在泡泡圖中用圖例說明泡泡大小所代表的讀數。
在圖中標注附加的圖像元素,如代表平均值的標示線、代表擬合的虛線曲線等。
備份數據、圖像文件和相關代碼。
在介紹一副數據圖時,也可以遵循一定的順序:
一句話說明畫了什么:“這幅圖描繪了湘北高中學生身高分布。”
說明坐標軸:“圖中橫軸代表了身高,縱軸代表了人數。”
說明主要圖像元素的含義:“每個豎條對應一定的身高區間。豎條的高度,代表了該身高區間內學生的人數。”
說明次要圖像元素的含義:“紅線代表了學生的平均身高。”
引導讀者深入解讀:“可以看到,學生身高大多集中在平均值附近……”
當然,對于存在人為創作因素的數據繪圖來說,也沒有定法。但建立一定的流程,能提高繪圖的效率。所以我也建議你建立自己的繪圖流程。
到此,關于“Python怎樣描繪數據”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。