標籤:

Pandas 數據結構簡介

Pandas 數據結構簡介知乎專欄 - 隨心寫作,自由表達

前段時間我說過我會寫一些關於 Pandas 的文章,但是我卻一直沒有跟進。然而,本周兩位同事向我表達了他們對於Pandas的學習興趣,因此我打算重新討論這個話題。

因為我覺得這是一個龐大的任務,所以下面我將分成三個部分來全面地介紹Pandas庫:

  • Part 1: Pandas數據結構簡介,該部分主要介紹該庫的兩個基本數據結構—— Series 和 DataFrames。
  • Part 2: DataFrames的使用方法,該部分主要介紹如何使用 DataFrames 的篩選、過濾、合併、聯合以及分組功能。
  • Part 3: 利用Pandas處理 MovieLens 數據集,該部分主要利用前兩部分的內容來回答關於 MovieLens 收視率數據的幾個基本分析的問題。

如果你想跟著文章的內容運行相應代碼的話,你可以在這裡下載到相關 CSV 數據和 MovieLens數據。

本篇文章的目的在於通過比較 Pandas 與 SQL 之間的差異來介紹該庫的基本用法。由於我的同事都非常熟悉 SQL 的語法,所以我覺得這是一個易於被讀者所理解的寫作方法。

如果你想要學習更多的 Pandas 知識,你可以閱讀 Pandas作者撰寫的書籍《Python for Data Analysis》。

Pandas是 Python中用於分析數據的常用開源庫。Python 可以很好地預處理和加工數據,但是它無法很好地進行數據分析——通常情況下你會利用 R 或者 SQL 來分析數據。有了 Pandas之後,我們可以利用 Python 快速地進行數據分析。

數據結構知乎專欄 - 隨心寫作,自由表達

Pandas中引入了兩種新的數據結構——Series和DataFrame,這兩種數據結構都建立在NumPy的基礎之上。

In [2]:

import pandas as pdnimport numpy as npnimport matplotlib.pyplot as pltnpd.set_option("max_columns", 50)n%matplotlib inlinen

Series知乎專欄 - 隨心寫作,自由表達

Series是指一個類似於數組、列表或列變數的一維對象,Series中每個條目都會被分配一個標籤索引。默認情況下,每個條目都會收到一個從0到N之間的索引標籤,其中N等於Series的長度減一。

In [3]:

# create a Series with an arbitrary listns = pd.Series([7, Heisenberg, 3.14, -1789710578, Happy Eating!])nsn

Out[3]:

0 7n1 Heisenbergn2 3.14n3 -1789710578n4 Happy Eating!ndtype: objectn

Series可以直接轉換詞典格式的數據,其中詞典的鍵值對應Series中的索引值。

In [4]:

d = {Chicago: 1000, New York: 1300, Portland: 900, San Francisco:1100, n Austin: 450, Boston: None}ncities = pd.Series(d)ncitiesn

Out[4]:

Austin 450nBoston NaNnChicago 1000nNew York 1300nPortland 900nSan Francisco 1100ndtype: float64n

你可以利用索引從Series中提取出特定的條目。

In [5]:

cities[Chicago]n

Out[5]:

1000.0n

In [6]:

cities[[Chicago, Portland, San Francisco]]n

Out[6]:

Chicago 1000nPortland 900nSan Francisco 1100ndtype: float64n

或者你也可以利用布爾索引值來選取數據。

In [7]:

cities[cities < 1000]n

Out[7]:

Austin 450nPortland 900ndtype: float64n

第二種方法可能看起來有點奇怪,所以讓我們更清楚地了解下它的邏輯——cities < 1000將返回一系列邏輯值,然後我們可以利用這些值從Series中提取出相應的條目。

In [8]:

less_than_1000 = cities < 1000nprint(less_than_1000)nprint(n)nprint(cities[less_than_1000])n

Austin TruenBoston FalsenChicago FalsenNew York FalsenPortland TruenSan Francisco Falsendtype: boolnnnAustin 450nPortland 900ndtype: float64n

我們還可以更改Series中的數值。

In [9]:

# changing based on the indexnprint(Old value, cities[Chicago])ncities[Chicago] = 1400nprint(New value, cities[Chicago])n

(Old value, 1000.0)n(New value, 1400.0)n

In [10]:

# changing values using boolean logicnprint(cities[cities < 1000])nprint(n)ncities[cities < 1000] = 750nprint(cities[cities < 1000])n

Austin 450nPortland 900ndtype: float64nnnAustin 750nPortland 750ndtype: float64n

如果你不確定Series中是否存在某個條目,你可以利用 Python 代碼來檢測。

In [11]:

print(Seattle in cities)nprint(San Francisco in cities)n

FalsenTruen

我們還可以對Series進行數學運算和函數運算。

In [12]:

# divide city value by 3ncities / 3n

Out[12]:

Austin 250.000000nBoston NaNnChicago 466.666667nNew York 433.333333nPortland 250.000000nSan Francisco 366.666667ndtype: float64n

In [13]:

# square city valuesnnp.square(cities)n

Out[13]:

Austin 562500nBoston NaNnChicago 1960000nNew York 1690000nPortland 562500nSan Francisco 1210000ndtype: float64n

此外你還可以匯總兩個Series,這會返回兩個Series的並集,其中沒有共同索引的條目將會返回 NULL/NaN。

In [14]:

print(cities[[Chicago, "New York", "Portland"]])nprint(n)nprint(cities[[Austin, New York]])nprint(n)nprint(cities[[Chicago, New York, Portland]] + cities[[Austin, New York]])n

Chicago 1400nNew York 1300nPortland 750ndtype: float64nnnAustin 750nNew York 1300ndtype: float64nnnAustin NaNnChicago NaNnNew York 2600nPortland NaNndtype: float64n

由於兩個Series中沒有同時包含Austin,Chicago和Portland,因此它們的返回值是 NULL/NaN。

我們可以利用 isnull 和 notnull 函數來檢測 NULL 值。

In [15]:

# returns a boolean series indicating which values arent NULLncities.notnull()n

Out[15]:

Austin TruenBoston FalsenChicago TruenNew York TruenPortland TruenSan Francisco Truendtype: booln

In [16]:

# use boolean logic to grab the NULL citiesnprint(cities.isnull())nprint(n)nprint(cities[cities.isnull()])n

Austin FalsenBoston TruenChicago FalsenNew York FalsenPortland FalsenSan Francisco Falsendtype: boolnnnBoston NaNndtype: float64n

DataFrame知乎專欄 - 隨心寫作,自由表達

DataFrame是一種由列向量和行向量組成的數據結構,它類似於電子數據表、資料庫表格和 R 語言中的 data.frame 對象。你也可以理解成DataFrame是由多個共享索引值的Series對象構成的。

本文的剩下篇幅中,我將主要介紹DataFrame的內容。

Reading Data知乎專欄 - 隨心寫作,自由表達

我們可以將 Python 中常用的數據結構(如詞典列表)轉換成DataFrame,其中通過控制columns的參數值可以調整變數的順序。默認情況下,DataFrame會按字母順序對變數進行排序。

In [18]:

data = {year: [2010, 2011, 2012, 2011, 2012, 2010, 2011, 2012],n team: [Bears, Bears, Bears, Packers, Packers, Lions, Lions, Lions],n wins: [11, 8, 10, 15, 11, 6, 10, 4],n losses: [5, 8, 6, 1, 5, 10, 6, 12]}nfootball = pd.DataFrame(data, columns=[year, team, wins, losses])nfootballn

Out[18]:

yearteamwinslosses02010Bears11512011Bears8822012Bears10632011Packers15142012Packers11552010Lions61062011Lions10672012Lions412

更多情況下,我們需要將數據集讀到DataFrame中,接下來我們將介紹幾種常用的讀取數據的方法。

CSV知乎專欄 - 隨心寫作,自由表達

我們可以利用read.csv函數來讀取 CSV 文件,其中read.csv函數默認CSV數據集是以逗號分隔的,你可以通過 sep 參數來控制分隔符的類別。

In [19]:

%cd ~/Desktop/n

/Users/zengphil/Desktopn

In [20]:

# Source: baseball-reference.com/players/r/riverma01.shtmln!head -n 5 mariano-rivera.csvn

Year,Age,Tm,Lg,W,L,W-L%,ERA,G,GS,GF,CG,SHO,SV,IP,H,R,ER,HR,BB,IBB,SO,HBP,BK,WP,BF,ERA+,FIP,WHIP,H9,HR9,BB9,SO9,SO/W,Awardsn1995,25,NYY,AL,5,3,.625,5.51,19,10,2,0,0,0,67.0,71,43,41,11,30,0,51,2,1,0,301,84,5.15,1.507,9.5,1.5,4.0,6.9,1.70,n1996,26,NYY,AL,8,3,.727,2.09,61,0,14,0,0,5,107.2,73,25,25,1,34,3,130,2,0,1,425,240,1.88,0.994,6.1,0.1,2.8,10.9,3.82,CYA-3MVP-12n1997 ,27,NYY,AL,6,4,.600,1.88,66,0,56,0,0,43,71.2,65,17,15,5,20,6,68,0,0,2,301,239,2.96,1.186,8.2,0.6,2.5,8.5,3.40,ASMVP-25n

In [23]:

from_csv = pd.read_csv(mariano-rivera.csv)nfrom_csv.head()n

Out[23]:

YearAgeTmLgWLW-L%ERAGGSGFCGSHOSVIPHRERHRBBIBBSOHBPBKWPBFERA+FIPWHIPH9HR9BB9SO9SO/WAwards0199525NYYAL53.6255.511910200067.07143411130051210301845.151.5079.51.54.06.91.70NaN1199626NYYAL83.7272.0961014005107.273252513431302014252401.880.9946.10.12.810.93.82CYA-3MVP-1221997 27NYYAL64.6001.8866056004371.26517155206680023012392.961.1868.20.62.58.53.40ASMVP-253199828NYYAL301.0001.9154049003661.14813133171361002462333.481.0607.00.42.55.32.12NaN41999 29NYYAL43.5711.8366063004569.04315142183523122682572.920.8845.60.32.36.82.89ASCYA-3MVP-14

該函數默認將文件中的第一行設定為列變數的標題,我們還可以設定 header=None 來手動設定列標題。

In [25]:

# Source: pro-football-reference.com/players/M/MannPe00/touchdowns/passing/2012/n!head -n 6 peython-passing-TDS-2012.csvn

Rk,G#,Date,Tm,,Opp,Result,Quarter,Dist,Scorer/Receiver,Score Before,Score Aftern1,1,2012-09-09,DEN,,PIT,W 31-19,3,71,Demaryius Thomas,Trail 7-13,Lead 14-13*n2,1,2012-09-09,DEN,,PIT,W 31-19,4,1,Jacob Tamme,Trail 14-19,Lead 22-19*n3,2,2012-09-17,DEN,@,ATL,L 21-27,2,17,Demaryius Thomas,Trail 0-20,Trail 7-20n4,3,2012-09-23,DEN,,HOU,L 25-31,4,38,Brandon Stokley,Trail 11-31,Trail 18-31n

In [27]:

cols = [num, game, date, team, home_away, opponent, n result, quarter, distance, receiver, score_before,n score_after]nno_headers = pd.read_csv(peython-passing-TDS-2012.csv, sep = ,,n header=None, names=cols)nno_headers.head()n

Out[27]:

numgamedateteamhome_awayopponentresultquarterdistancereceiverscore_beforescore_after0RkG#DateTmNaNOppResultQuarterDistScorer/ReceiverScore BeforeScore After1112012-09-09DENNaNPITW 31-19371Demaryius ThomasTrail 7-13Lead 14-13*2212012-09-09DENNaNPITW 31-1941Jacob TammeTrail 14-19Lead 22-19*3322012-09-17DEN@ATLL 21-27217Demaryius ThomasTrail 0-20Trail 7-204432012-09-23DENNaNHOUL 25-31438Brandon StokleyTrail 11-31Trail 18-31

Pandas的reader系列函數中有許多可控參數,用於控制讀取數據時的其他設定。

大家可以參閱IO文檔來熟悉文件讀取/寫入功能。

Excel知乎專欄 - 隨心寫作,自由表達

你們討厭VBA嗎?我非常討厭它,我相信你也會討厭它的。幸運的是,pandas允許我們讀寫 Excel 文件,所以我們可以利用Python處理完數據後再導出Excel文件,這樣可以規避使用煩人的VBA來處理數據。

讀取Excel文件需要安裝xlrd庫,我們可以利用pip工具來安裝它(pip install xlrd)。

In [28]:

# this is the DataFrame we created from a dictionary earliernfootball.head()n

Out[28]:

yearteamwinslosses02010Bears11512011Bears8822012Bears10632011Packers15142012Packers115

In [29]:

# since our index on the football DataFrame is meaningless, lets not write itnfootball.to_excel(football.xlsx, index=False)n

In [32]:

!ls -l *.xlsxn

-rw-r--r-- 1 zengphil staff 5588 4 23 10:56 football.xlsxn

In [33]:

# delete the DataFramendel footballn

In [35]:

# read from Excelnfootball = pd.read_excel(football.xlsx, Sheet1)nfootballn

Out[35]:

yearteamwinslosses02010Bears11512011Bears8822012Bears10632011Packers15142012Packers11552010Lions61062011Lions10672012Lions412

Database知乎專欄 - 隨心寫作,自由表達

Pandas還可以直接從資料庫中讀寫DataFrame文件,你只需要利用pandas.io模塊中的read_sql或to_sql函數來創建一個連接資料庫的對象即可。

需要注意的是,to_sql直接調用INSERT INTO語句,因此數據的傳輸速度比較慢。如果你想將一個大型DataFrame寫入資料庫中,最好先導出CSV文件然後再導入資料庫中。

In [38]:

from pandas.io import sqlnimport sqlite3nnconn = sqlite3.connect(/Users/zengphil/Downloads/Database)nquery = "SELECT * FROM towed WHERE make = FORD;"nnresults = sql.read_sql(query, con = conn)nresults.head()n

Clipboard知乎專欄 - 隨心寫作,自由表達

相比於直接將查詢結果插入DataFrame中,我更傾向於從剪貼板中讀取數據。Python可以很好地處理剪貼板中的分隔符數據,你可以控制sep參數來設定數據分隔符。

Hank Aaron

In [39]:

hank = pd.read_clipboard()nhank.head()n

Out[39]:

195420MLNNL12250946858131276136922.12839.280.322.447.76910420913.136.14Unnamed: 27*79RoY-401955 21MLNNL153665602105189379271063149610.3140.3660.5400.906141325203745*974AS,MVP-911956 22MLNNL153660609106200341426922437540.3280.3650.5580.923151340212576*9AS,MVP-321957 23MLNNL151675615118198276441321157580.3220.3780.6000.9781663691300315*98AS,MVP-131958 24MLNNL15366460110919634430954159490.3260.3860.5460.9311523282110316*98AS,MVP-3,GG41959 25MLNNL154693629116223467391238051540.3550.4010.6361.0371824001940917*98/5AS,MVP-3,GG

URL知乎專欄 - 隨心寫作,自由表達

此外,我們還可以利用read_table函數直接從 URL 鏈接中讀取數據。

In [40]:

url = https://raw.github.com/gjreda/best-sandwiches/master/data/best-sandwiches-geocode.tsvnn# fetch the text from the URL and read it into a DataFramenfrom_url = pd.read_table(url, sep=t)nfrom_url.head(3)n

Out[40]:

ranksandwichrestaurantdescriptionpriceaddresscityphonewebsitefull_addressformatted_addresslatlng01BLTOld Oak TapThe B is applewood smoked—nice and snapp...$102109 W. Chicago Ave.Chicago773-772-0406theoldoaktap.com2109 W. Chicago Ave., Chicago2109 West Chicago Avenue, Chicago, IL 60622, USA41.895734-87.67996012Fried BolognaAu ChevalThought your bologna-eating days had retired w...$9800 W. Randolph St.Chicago312-929-4580aucheval.tumblr.com800 W. Randolph St., Chicago800 West Randolph Street, Chicago, IL 60607, USA41.884672-87.64775423Woodland MushroomXocoLeave it to Rick Bayless and crew to come up w...$9.50.445 N. Clark St.Chicago312-334-3688rickbayless.com445 N. Clark St., Chicago445 North Clark Street, Chicago, IL 60654, USA41.890602-87.630925

Google Analytics知乎專欄 - 隨心寫作,自由表達

Pandas還整合了 Google Analytics 的API介面,但是需要進行一些設置。本文沒有介紹這些內容,你可以參閱文章1和文章2。

weixin.qq.com/r/WkMCGqv (二維碼自動識別)

原文鏈接:Intro to pandas data structures

原文作者:Greg Reda

譯者:Fibears


推薦閱讀:

centos在python3環境下安裝PIP的問題?
薦書:《Fluent Python》
Python3.4 用 pip 安裝lxml時出現 「Unable to find vcvarsall.bat 」?
學習數據分析的8個 pandas資源

TAG:Python |