pandas提供了一些用于將表格型數(shù)據(jù)讀取為DataFrame對(duì)象的函數(shù)鳞溉。表6-1對(duì)它們進(jìn)行了總結(jié)峻堰,其中read_csv和read_table可能會(huì)是你今后用得最多的。
我將大致介紹一下這些函數(shù)在將文本數(shù)據(jù)轉(zhuǎn)換為DataFrame時(shí)所用到的一些技術(shù)。這些函數(shù)的選項(xiàng)可以劃分為以下幾個(gè)大類:
- 索引:將一個(gè)或多個(gè)列當(dāng)做返回的DataFrame處理络断,以及是否從文件汹碱、用戶獲取列名粘衬。
- 類型推斷和數(shù)據(jù)轉(zhuǎn)換:包括用戶定義值的轉(zhuǎn)換、和自定義的缺失值標(biāo)記列表等咳促。
- 日期解析:包括組合功能稚新,比如將分散在多個(gè)列中的日期時(shí)間信息組合成結(jié)果中的單個(gè)列。
- 迭代:支持對(duì)大文件進(jìn)行逐塊迭代跪腹。
- 不規(guī)整數(shù)據(jù)問題:跳過一些行褂删、頁腳、注釋或其他一些不重要的東西(比如由成千上萬個(gè)逗號(hào)隔開的數(shù)值數(shù)據(jù))冲茸。
因?yàn)楣ぷ髦袑?shí)際碰到的數(shù)據(jù)可能十分混亂屯阀,一些數(shù)據(jù)加載函數(shù)(尤其是read_csv)的選項(xiàng)逐漸變得復(fù)雜起來。面對(duì)不同的參數(shù)轴术,感到頭痛很正常(read_csv有超過50個(gè)參數(shù))难衰。pandas文檔有這些參數(shù)的例子,如果你感到閱讀某個(gè)文件很難逗栽,可以通過相似的足夠多的例子找到正確的參數(shù)盖袭。
其中一些函數(shù),比如pandas.read_csv彼宠,有類型推斷功能鳄虱,因?yàn)榱袛?shù)據(jù)的類型不屬于數(shù)據(jù)類型。也就是說凭峡,你不需要指定列的類型到底是數(shù)值拙已、整數(shù)、布爾值摧冀,還是字符串倍踪。其它的數(shù)據(jù)格式系宫,如HDF5、Feather和msgpack惭适,會(huì)在格式中存儲(chǔ)數(shù)據(jù)類型笙瑟。
日期和其他自定義類型的處理需要多花點(diǎn)工夫才行。首先我們來看一個(gè)以逗號(hào)分隔的(CSV)文本文件:
In [8]: !cat examples/ex1.csv
a,b,c,d,message
1,2,3,4,hello
5,6,7,8,world
9,10,11,12,foo
筆記:這里癞志,我用的是Unix的cat shell命令將文件的原始內(nèi)容打印到屏幕上往枷。如果你用的是Windows,你可以使用type達(dá)到同樣的效果凄杯。
由于該文件以逗號(hào)分隔错洁,所以我們可以使用read_csv將其讀入一個(gè)DataFrame:
In [9]: df = pd.read_csv('examples/ex1.csv')
In [10]: df
Out[10]:
a b c d message
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo
我們還可以使用read_table,并指定分隔符:
In [11]: pd.read_table('examples/ex1.csv', sep=',')
Out[11]:
a b c d message
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo
并不是所有文件都有標(biāo)題行戒突⊥筒辏看看下面這個(gè)文件:
In [12]: !cat examples/ex2.csv
1,2,3,4,hello
5,6,7,8,world
9,10,11,12,foo
讀入該文件的辦法有兩個(gè)。你可以讓pandas為其分配默認(rèn)的列名膊存,也可以自己定義列名:
In [13]: pd.read_csv('examples/ex2.csv', header=None)
Out[13]:
0 1 2 3 4
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo
In [14]: pd.read_csv('examples/ex2.csv', names=['a', 'b', 'c', 'd', 'message'])
Out[14]:
a b c d message
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo
假設(shè)你希望將message列做成DataFrame的索引导而。你可以明確表示要將該列放到索引4的位置上,也可以通過index_col參數(shù)指定"message":
In [15]: names = ['a', 'b', 'c', 'd', 'message']
In [16]: pd.read_csv('examples/ex2.csv', names=names, index_col='message')
Out[16]:
a b c d
message
hello 1 2 3 4
world 5 6 7 8
foo 9 10 11 12
如果希望將多個(gè)列做成一個(gè)層次化索引隔崎,只需傳入由列編號(hào)或列名組成的列表即可:
In [17]: !cat examples/csv_mindex.csv
key1,key2,value1,value2
one,a,1,2
one,b,3,4
one,c,5,6
one,d,7,8
two,a,9,10
two,b,11,12
two,c,13,14
two,d,15,16
In [18]: parsed = pd.read_csv('examples/csv_mindex.csv',
....: index_col=['key1', 'key2'])
In [19]: parsed
Out[19]:
value1 value2
key1 key2
one a 1 2
b 3 4
c 5 6
d 7 8
two a 9 10
b 11 12
c 13 14
d 15 16
有些情況下今艺,有些表格可能不是用固定的分隔符去分隔字段的(比如空白符或其它模式)【糇洌看看下面這個(gè)文本文件:
In [20]: list(open('examples/ex3.txt'))
Out[20]:
[' A B C\n',
'aaa -0.264438 -1.026059 -0.619500\n',
'bbb 0.927272 0.302904 -0.032399\n',
'ccc -0.264273 -0.386314 -0.217601\n',
'ddd -0.871858 -0.348382 1.100491\n']
雖然可以手動(dòng)對(duì)數(shù)據(jù)進(jìn)行規(guī)整虚缎,這里的字段是被數(shù)量不同的空白字符間隔開的。這種情況下钓株,你可以傳遞一個(gè)正則表達(dá)式作為read_table的分隔符实牡。可以用正則表達(dá)式表達(dá)為\s+轴合,于是有:
In [21]: result = pd.read_table('examples/ex3.txt', sep='\s+')
In [22]: result
Out[22]:
A B C
aaa -0.264438 -1.026059 -0.619500
bbb 0.927272 0.302904 -0.032399
ccc -0.264273 -0.386314 -0.217601
ddd -0.871858 -0.348382 1.100491
```這里创坞,由于列名比數(shù)據(jù)行的數(shù)量少,所以read_table推斷第一列應(yīng)該是DataFrame的索引值桩。
這些解析器函數(shù)還有許多參數(shù)可以幫助你處理各種各樣的異形文件格式(表6-2列出了一些)摆霉。比如說,你可以用skiprows跳過文件的第一行奔坟、第三行和第四行:
```py
In [23]: !cat examples/ex4.csv
# hey!
a,b,c,d,message
# just wanted to make things more difficult for you
# who reads CSV files with computers, anyway?
1,2,3,4,hello
5,6,7,8,world
9,10,11,12,foo
In [24]: pd.read_csv('examples/ex4.csv', skiprows=[0, 2, 3])
Out[24]:
a b c d message
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo
缺失值處理是文件解析任務(wù)中的一個(gè)重要組成部分。缺失數(shù)據(jù)經(jīng)常是要么沒有(空字符串)搭盾,要么用某個(gè)標(biāo)記值表示咳秉。默認(rèn)情況下,pandas會(huì)用一組經(jīng)常出現(xiàn)的標(biāo)記值進(jìn)行識(shí)別鸯隅,比如NA及NULL:
In [25]: !cat examples/ex5.csv
something,a,b,c,d,message
one,1,2,3,4,NA
two,5,6,,8,world
three,9,10,11,12,foo
In [26]: result = pd.read_csv('examples/ex5.csv')
In [27]: result
Out[27]:
something a b c d message
0 one 1 2 3.0 4 NaN
1 two 5 6 NaN 8 world
2 three 9 10 11.0 12 foo
In [28]: pd.isnull(result)
Out[28]:
something a b c d message
0 False False False False False True
1 False False False True False False
2 False False False False False False
na_values可以用一個(gè)列表或集合的字符串表示缺失值:
In [29]: result = pd.read_csv('examples/ex5.csv', na_values=['NULL'])
In [30]: result
Out[30]:
something a b c d message
0 one 1 2 3.0 4 NaN
1 two 5 6 NaN 8 world
2 three 9 10 11.0 12 foo
這里的NaN不應(yīng)該是NULL么澜建?是編輯錯(cuò)誤向挖?
字典的各列可以使用不同的NA標(biāo)記值:
In [31]: sentinels = {'message': ['foo', 'NA'], 'something': ['two']}
In [32]: pd.read_csv('examples/ex5.csv', na_values=sentinels)
Out[32]:
something a b c d message
0 one 1 2 3.0 4 NaN
1 NaN 5 6 NaN 8 world
2 three 9 10 11.0 12 NaN
表6-2列出了pandas.read_csv和pandas.read_table常用的選項(xiàng)。
在處理很大的文件時(shí)炕舵,或找出大文件中的參數(shù)集以便于后續(xù)處理時(shí)何之,你可能只想讀取文件的一小部分或逐塊對(duì)文件進(jìn)行迭代。
在看大文件之前咽筋,我們先設(shè)置pandas顯示地更緊些:
In [33]: pd.options.display.max_rows = 10
然后有:
In [34]: result = pd.read_csv('examples/ex6.csv')
In [35]: result
Out[35]:
one two three four key
0 0.467976 -0.038649 -0.295344 -1.824726 L
1 -0.358893 1.404453 0.704965 -0.200638 B
2 -0.501840 0.659254 -0.421691 -0.057688 G
3 0.204886 1.074134 1.388361 -0.982404 R
4 0.354628 -0.133116 0.283763 -0.837063 Q
... ... ... ... ... ..
9995 2.311896 -0.417070 -1.409599 -0.515821 L
9996 -0.479893 -0.650419 0.745152 -0.646038 E
9997 0.523331 0.787112 0.486066 1.093156 K
9998 -0.362559 0.598894 -1.843201 0.887292 G
9999 -0.096376 -1.012999 -0.657431 -0.573315 0
[10000 rows x 5 columns]
If you want to only read a small
如果只想讀取幾行(避免讀取整個(gè)文件)溶推,通過nrows進(jìn)行指定即可:
In [36]: pd.read_csv('examples/ex6.csv', nrows=5)
Out[36]:
one two three four key
0 0.467976 -0.038649 -0.295344 -1.824726 L
1 -0.358893 1.404453 0.704965 -0.200638 B
2 -0.501840 0.659254 -0.421691 -0.057688 G
3 0.204886 1.074134 1.388361 -0.982404 R
4 0.354628 -0.133116 0.283763 -0.837063 Q
要逐塊讀取文件,可以指定chunksize(行數(shù)):
In [874]: chunker = pd.read_csv('ch06/ex6.csv', chunksize=1000)
In [875]: chunker
Out[875]: <pandas.io.parsers.TextParser at 0x8398150>
read_csv所返回地這個(gè)TextParser對(duì)象使你可以根據(jù)chunksize對(duì)文件進(jìn)行逐塊迭代奸攻。比如說蒜危,我們可以迭代處理ex6.csv將值計(jì)數(shù)聚合到‘key’列中,如下所示:
chunker = pd.read_csv('examples/ex6.csv', chunksize=1000)
tot = pd.Series([])
for piece in chunker:
tot = tot.add(piece['key'].value_counts(), fill_value=0)
tot = tot.sort_values(ascending=False)
然后有:
In [40]: tot[:10]
Out[40]:
E 368.0
X 364.0
L 346.0
O 343.0
Q 340.0
M 338.0
J 337.0
F 335.0
K 334.0
H 330.0
dtype: float64
數(shù)據(jù)也可以被輸出為分隔符格式的文本睹耐。我們?cè)賮砜纯粗白x過的一個(gè)CSV文件:
In [41]: data = pd.read_csv('examples/ex5.csv')
In [42]: data
Out[42]:
something a b c d message
0 one 1 2 3.0 4 NaN
1 two 5 6 NaN 8 world
2 three 9 10 11.0 12 foo
利用DataFrame的to_csv方法辐赞,我們可以將數(shù)據(jù)寫到一個(gè)以逗號(hào)分隔的文件中:
In [43]: data.to_csv('examples/out.csv')
In [44]: !cat examples/out.csv
,something,a,b,c,d,message
0,one,1,2,3.0,4,
1,two,5,6,,8,world
2,three,9,10,11.0,12,foo
當(dāng)然,還可以使用其他分隔符(由于這里直接寫出到sys.stdout硝训,所以僅僅是打印出文本結(jié)果而已):
In [45]: import sys
In [46]: data.to_csv(sys.stdout, sep='|')
|something|a|b|c|d|message
0|one|1|2|3.0|4|
1|two|5|6||8|world
2|three|9|10|11.0|12|foo
print是sys.stdout的高級(jí)封裝响委,包含了sys.stdout.write以及一個(gè)換行符,實(shí)際上就是輸出到了控制臺(tái)中窖梁,并沒有輸出到文件中药有,所以只打印了文本結(jié)果。
缺失值在輸出結(jié)果中會(huì)被表示為空字符串账千。你可能希望將其表示為別的標(biāo)記值:
In [47]: data.to_csv(sys.stdout, na_rep='NULL')
,something,a,b,c,d,message
0,one,1,2,3.0,4,NULL
1,two,5,6,NULL,8,world
2,three,9,10,11.0,12,foo
如果沒有設(shè)置其他選項(xiàng)成洗,則會(huì)寫出行和列的標(biāo)簽。當(dāng)然彰导,它們也都可以被禁用:
In [48]: data.to_csv(sys.stdout, index=False, header=False)
one,1,2,3.0,4,
two,5,6,,8,world
three,9,10,11.0,12,foo
此外蛔翅,你還可以只寫出一部分的列,并以你指定的順序排列:
In [49]: data.to_csv(sys.stdout, index=False, columns=['a', 'b', 'c'])
a,b,c
1,2,3.0
5,6,
9,10,11.0
Series也有一個(gè)to_csv方法:
In [50]: dates = pd.date_range('1/1/2000', periods=7)
In [51]: ts = pd.Series(np.arange(7), index=dates)
In [52]: ts.to_csv('examples/tseries.csv')
In [53]: !cat examples/tseries.csv
2000-01-01,0
2000-01-02,1
2000-01-03,2
2000-01-04,3
2000-01-05,4
2000-01-06,5
2000-01-07,6
pandas.read_json可以自動(dòng)將特別格式的JSON數(shù)據(jù)集轉(zhuǎn)換為Series或DataFrame位谋。例如:
In [68]: !cat examples/example.json
[{"a": 1, "b": 2, "c": 3},
{"a": 4, "b": 5, "c": 6},
{"a": 7, "b": 8, "c": 9}]
pandas.read_json的默認(rèn)選項(xiàng)假設(shè)JSON數(shù)組中的每個(gè)對(duì)象是表格中的一行:
In [69]: data = pd.read_json('examples/example.json')
In [70]: data
Out[70]:
a b c
0 1 2 3
1 4 5 6
2 7 8 9
如果你需要將數(shù)據(jù)從pandas輸出到JSON山析,可以使用to_json方法:
In [71]: print(data.to_json())
{"a":{"0":1,"1":4,"2":7},"b":{"0":2,"1":5,"2":8},"c":{"0":3,"1":6,"2":9}}
In [72]: print(data.to_json(orient='records'))
[{"a":1,"b":2,"c":3},{"a":4,"b":5,"c":6},{"a":7,"b":8,"c":9}]
records應(yīng)該就是按行輸出吧。
pandas有一個(gè)內(nèi)置的功能掏父,read_html笋轨,它可以使用lxml和Beautiful Soup自動(dòng)將HTML文件中的表格解析為DataFrame對(duì)象。為了進(jìn)行展示赊淑,我從美國(guó)聯(lián)邦存款保險(xiǎn)公司下載了一個(gè)HTML文件(pandas文檔中也使用過)爵政,它記錄了銀行倒閉的情況。首先陶缺,你需要安裝read_html用到的庫:
conda install lxml
pip install beautifulsoup4 html5lib
如果你用的不是conda钾挟,可以使用pip install lxml。
pandas.read_html有一些選項(xiàng)饱岸,默認(rèn)條件下掺出,它會(huì)搜索徽千、嘗試解析<table>標(biāo)簽內(nèi)的的表格數(shù)據(jù)。結(jié)果是一個(gè)列表的DataFrame對(duì)象:
In [73]: tables = pd.read_html('examples/fdic_failed_bank_list.html')
In [74]: len(tables)
Out[74]: 1
In [75]: failures = tables[0]
In [76]: failures.head()
Out[76]:
Bank Name City ST CERT \
0 Allied Bank Mulberry AR 91
1 The Woodbury Banking Company Woodbury GA 11297
2 First CornerStone Bank King of Prussia PA 35312
3 Trust Company Bank Memphis TN 9956
4 North Milwaukee State Bank Milwaukee WI 20364
Acquiring Institution Closing Date Updated Date
0 Today's Bank September 23, 2016 November 17, 2016
1 United Bank August 19, 2016 November 17, 2016
2 First-Citizens Bank & Trust Company May 6, 2016 September 6, 2016
3 The Bank of Fayette County April 29, 2016 September 6, 2016
4 First-Citizens Bank & Trust Company March 11, 2016 June 16, 2016
因?yàn)閒ailures有許多列汤锨,pandas插入了一個(gè)換行符\双抽。
這里,我們可以做一些數(shù)據(jù)清洗和分析(后面章節(jié)會(huì)進(jìn)一步講解)闲礼,比如計(jì)算按年份計(jì)算倒閉的銀行數(shù):
In [77]: close_timestamps = pd.to_datetime(failures['Closing Date'])
In [78]: close_timestamps.dt.year.value_counts()
Out[78]:
2010 157
2009 140
2011 92
2012 51
2008 25
...
2004 4
2001 4
2007 3
2003 3
2000 2
Name: Closing Date, Length: 15, dtype: int64
實(shí)現(xiàn)數(shù)據(jù)的高效二進(jìn)制格式存儲(chǔ)最簡(jiǎn)單的辦法之一是使用Python內(nèi)置的pickle序列化牍汹。pandas對(duì)象都有一個(gè)用于將數(shù)據(jù)以pickle格式保存到磁盤上的to_pickle方法:
In [87]: frame = pd.read_csv('examples/ex1.csv')
In [88]: frame
Out[88]:
a b c d message
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo
In [89]: frame.to_pickle('examples/frame_pickle')
你可以通過pickle直接讀取被pickle化的數(shù)據(jù),或是使用更為方便的pandas.read_pickle:
In [90]: pd.read_pickle('examples/frame_pickle')
Out[90]:
a b c d message
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo
.>注意:pickle僅建議用于短期存儲(chǔ)格式位仁。其原因是很難保證該格式永遠(yuǎn)是穩(wěn)定的柑贞;今天pickle的對(duì)象可能無法被后續(xù)版本的庫unpickle出來。雖然我盡力保證這種事情不會(huì)發(fā)生在pandas中聂抢,但是今后的某個(gè)時(shí)候說不定還是得“打破”該pickle格式钧嘶。
pandas內(nèi)置支持兩個(gè)二進(jìn)制數(shù)據(jù)格式:HDF5和MessagePack。下一節(jié)琳疏,我會(huì)給出幾個(gè)HDF5的例子有决,但我建議你嘗試下不同的文件格式,看看它們的速度以及是否適合你的分析工作空盼。pandas或NumPy數(shù)據(jù)的其它存儲(chǔ)格式有:
- bcolz:一種可壓縮的列存儲(chǔ)二進(jìn)制格式书幕,基于Blosc壓縮庫。
- Feather:我與R語言社區(qū)的Hadley Wickham設(shè)計(jì)的一種跨語言的列存儲(chǔ)文件格式揽趾。Feather使用了Apache Arrow的列式內(nèi)存格式台汇。
HDF5是一種存儲(chǔ)大規(guī)模科學(xué)數(shù)組數(shù)據(jù)的非常好的文件格式篱瞎。它可以被作為C標(biāo)準(zhǔn)庫苟呐,帶有許多語言的接口,如Java俐筋、Python和MATLAB等牵素。HDF5中的HDF指的是層次型數(shù)據(jù)格式(hierarchical data format)。每個(gè)HDF5文件都含有一個(gè)文件系統(tǒng)式的節(jié)點(diǎn)結(jié)構(gòu)澄者,它使你能夠存儲(chǔ)多個(gè)數(shù)據(jù)集并支持元數(shù)據(jù)笆呆。與其他簡(jiǎn)單格式相比,HDF5支持多種壓縮器的即時(shí)壓縮粱挡,還能更高效地存儲(chǔ)重復(fù)模式數(shù)據(jù)赠幕。對(duì)于那些非常大的無法直接放入內(nèi)存的數(shù)據(jù)集,HDF5就是不錯(cuò)的選擇询筏,因?yàn)樗梢愿咝У胤謮K讀寫劣坊。
雖然可以用PyTables或h5py庫直接訪問HDF5文件,pandas提供了更為高級(jí)的接口屈留,可以簡(jiǎn)化存儲(chǔ)Series和DataFrame對(duì)象局冰。HDFStore類可以像字典一樣,處理低級(jí)的細(xì)節(jié):
In [92]: frame = pd.DataFrame({'a': np.random.randn(100)})
In [93]: store = pd.HDFStore('mydata.h5')
In [94]: store['obj1'] = frame
In [95]: store['obj1_col'] = frame['a']
In [96]: store
Out[96]:
<class 'pandas.io.pytables.HDFStore'>
File path: mydata.h5
/obj1 frame (shape->[100,1])
/obj1_col series (shape->[100])
/obj2 frame_table (typ->appendable,nrows->100,ncols->1,indexers->
[index])
/obj3 frame_table (typ->appendable,nrows->100,ncols->1,indexers->
[index])
HDF5文件中的對(duì)象可以通過與字典一樣的API進(jìn)行獲裙辔!:
In [97]: store['obj1']
Out[97]:
a
0 -0.204708
1 0.478943
2 -0.519439
3 -0.555730
4 1.965781
.. ...
95 0.795253
96 0.118110
97 -0.748532
98 0.584970
99 0.152677
[100 rows x 1 columns]
HDFStore支持兩種存儲(chǔ)模式康二,'fixed'和'table'。后者通常會(huì)更慢勇蝙,但是支持使用特殊語法進(jìn)行查詢操作:
In [98]: store.put('obj2', frame, format='table')
In [99]: store.select('obj2', where=['index >= 10 and index <= 15'])
Out[99]:
a
10 1.007189
11 -1.296221
12 0.274992
13 0.228913
14 1.352917
15 0.886429
In [100]: store.close()
put是store['obj2'] = frame方法的顯示版本沫勿,允許我們?cè)O(shè)置其它的選項(xiàng),比如格式味混。
pandas.read_hdf函數(shù)可以快捷使用這些工具:
In [101]: frame.to_hdf('mydata.h5', 'obj3', format='table')
In [102]: pd.read_hdf('mydata.h5', 'obj3', where=['index < 5'])
Out[102]:
a
0 -0.204708
1 0.478943
2 -0.519439
3 -0.555730
4 1.965781
筆記:如果你要處理的數(shù)據(jù)位于遠(yuǎn)程服務(wù)器产雹,比如Amazon S3或HDFS,使用專門為分布式存儲(chǔ)(比如Apache Parquet)的二進(jìn)制格式也許更加合適翁锡。Python的Parquet和其它存儲(chǔ)格式還在不斷的發(fā)展之中蔓挖,所以這本書中沒有涉及。
如果需要本地處理海量數(shù)據(jù)馆衔,我建議你好好研究一下PyTables和h5py瘟判,看看它們能滿足你的哪些需求。角溃。由于許多數(shù)據(jù)分析問題都是IO密集型(而不是CPU密集型)拷获,利用HDF5這樣的工具能顯著提升應(yīng)用程序的效率。
注意:HDF5不是數(shù)據(jù)庫。它最適合用作“一次寫多次讀”的數(shù)據(jù)集未蝌。雖然數(shù)據(jù)可以在任何時(shí)候被添加到文件中驮吱,但如果同時(shí)發(fā)生多個(gè)寫操作,文件就可能會(huì)被破壞树埠。
pandas的ExcelFile類或pandas.read_excel函數(shù)支持讀取存儲(chǔ)在Excel 2003(或更高版本)中的表格型數(shù)據(jù)糠馆。這兩個(gè)工具分別使用擴(kuò)展包xlrd和openpyxl讀取XLS和XLSX文件。你可以用pip或conda安裝它們怎憋。
要使用ExcelFile又碌,通過傳遞xls或xlsx路徑創(chuàng)建一個(gè)實(shí)例:
In [104]: xlsx = pd.ExcelFile('examples/ex1.xlsx')
存儲(chǔ)在表單中的數(shù)據(jù)可以read_excel讀取到DataFrame(原書這里寫的是用parse解析,但代碼中用的是read_excel绊袋,是個(gè)筆誤:只換了代碼毕匀,沒有改文字):
In [105]: pd.read_excel(xlsx, 'Sheet1')
Out[105]:
a b c d message
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo
如果要讀取一個(gè)文件中的多個(gè)表單,創(chuàng)建ExcelFile會(huì)更快癌别,但你也可以將文件名傳遞到pandas.read_excel:
In [106]: frame = pd.read_excel('examples/ex1.xlsx', 'Sheet1')
In [107]: frame
Out[107]:
a b c d message
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo
如果要將pandas數(shù)據(jù)寫入為Excel格式皂岔,你必須首先創(chuàng)建一個(gè)ExcelWriter,然后使用pandas對(duì)象的to_excel方法將數(shù)據(jù)寫入到其中:
In [108]: writer = pd.ExcelWriter('examples/ex2.xlsx')
In [109]: frame.to_excel(writer, 'Sheet1')
In [110]: writer.save()
你還可以不使用ExcelWriter展姐,而是傳遞文件的路徑到to_excel:
In [111]: frame.to_excel('examples/ex2.xlsx')
許多網(wǎng)站都有一些通過JSON或其他格式提供數(shù)據(jù)的公共API躁垛。通過Python訪問這些API的辦法有不少剖毯。一個(gè)簡(jiǎn)單易用的辦法(推薦)是requests包(http://docs.python-requests.org)。
為了搜索最新的30個(gè)GitHub上的pandas主題教馆,我們可以發(fā)一個(gè)HTTP GET請(qǐng)求逊谋,使用requests擴(kuò)展庫:
In [113]: import requests
In [114]: url = 'https://api.github.com/repos/pandas-dev/pandas/issues'
In [115]: resp = requests.get(url)
In [116]: resp
Out[116]: <Response [200]>
響應(yīng)對(duì)象的json方法會(huì)返回一個(gè)包含被解析過的JSON字典,加載到一個(gè)Python對(duì)象中:
In [117]: data = resp.json()
In [118]: data[0]['title']
Out[118]: 'Period does not round down for frequencies less that 1 hour'
data中的每個(gè)元素都是一個(gè)包含所有GitHub主題頁數(shù)據(jù)(不包含評(píng)論)的字典土铺。我們可以直接傳遞數(shù)據(jù)到DataFrame胶滋,并提取感興趣的字段:
In [119]: issues = pd.DataFrame(data, columns=['number', 'title',
.....: 'labels', 'state'])
In [120]: issues
Out[120]:
number title \
0 17666 Period does not round down for frequencies les...
1 17665 DOC: improve docstring of function where
2 17664 COMPAT: skip 32-bit test on int repr
3 17662 implement Delegator class
4 17654 BUG: Fix series rename called with str alterin...
.. ... ...
25 17603 BUG: Correctly localize naive datetime strings...
26 17599 core.dtypes.generic --> cython
27 17596 Merge cdate_range functionality into bdate_range
28 17587 Time Grouper bug fix when applied for list gro...
29 17583 BUG: fix tz-aware DatetimeIndex + TimedeltaInd...
labels state
0 [] open
1 [{'id': 134699, 'url': 'https://api.github.com... open
2 [{'id': 563047854, 'url': 'https://api.github.... open
3 [] open
4 [{'id': 76811, 'url': 'https://api.github.com/... open
.. ... ...
25 [{'id': 76811, 'url': 'https://api.github.com/... open
26 [{'id': 49094459, 'url': 'https://api.github.c... open
27 [{'id': 35818298, 'url': 'https://api.github.c... open
28 [{'id': 233160, 'url': 'https://api.github.com... open
29 [{'id': 76811, 'url': 'https://api.github.com/... open
[30 rows x 4 columns]
花費(fèi)一些精力,你就可以創(chuàng)建一些更高級(jí)的常見的Web API的接口悲敷,返回DataFrame對(duì)象究恤,方便進(jìn)行分析。
說白了后德,WebApi就是用其他第三方庫獲取數(shù)據(jù)然后用DataFrame展示出來部宿。
*接下來涉及數(shù)據(jù)庫的內(nèi)容,沒學(xué)過數(shù)據(jù)庫啊探遵,待定吧窟赏,等需要用的時(shí)候再補(bǔ)充。
在商業(yè)場(chǎng)景下箱季,大多數(shù)數(shù)據(jù)可能不是存儲(chǔ)在文本或Excel文件中涯穷。基于SQL的關(guān)系型數(shù)據(jù)庫(如SQL Server藏雏、PostgreSQL和MySQL等)使用非常廣泛拷况,其它一些數(shù)據(jù)庫也很流行。數(shù)據(jù)庫的選擇通常取決于性能掘殴、數(shù)據(jù)完整性以及應(yīng)用程序的伸縮性需求赚瘦。
將數(shù)據(jù)從SQL加載到DataFrame的過程很簡(jiǎn)單,此外pandas還有一些能夠簡(jiǎn)化該過程的函數(shù)奏寨。例如起意,我將使用SQLite數(shù)據(jù)庫(通過Python內(nèi)置的sqlite3驅(qū)動(dòng)器):
In [121]: import sqlite3
In [122]: query = """
.....: CREATE TABLE test
.....: (a VARCHAR(20), b VARCHAR(20),
.....: c REAL, d INTEGER
.....: );"""
In [123]: con = sqlite3.connect('mydata.sqlite')
In [124]: con.execute(query)
Out[124]: <sqlite3.Cursor at 0x7f6b12a50f10>
In [125]: con.commit()
···
然后插入幾行數(shù)據(jù):
```py
In [126]: data = [('Atlanta', 'Georgia', 1.25, 6),
.....: ('Tallahassee', 'Florida', 2.6, 3),
.....: ('Sacramento', 'California', 1.7, 5)]
In [127]: stmt = "INSERT INTO test VALUES(?, ?, ?, ?)"
In [128]: con.executemany(stmt, data)
Out[128]: <sqlite3.Cursor at 0x7f6b15c66ce0>
從表中選取數(shù)據(jù)時(shí),大部分Python SQL驅(qū)動(dòng)器(PyODBC病瞳、psycopg2揽咕、MySQLdb、pymssql等)都會(huì)返回一個(gè)元組列表:
In [130]: cursor = con.execute('select * from test')
In [131]: rows = cursor.fetchall()
In [132]: rows
Out[132]:
[('Atlanta', 'Georgia', 1.25, 6),
('Tallahassee', 'Florida', 2.6, 3),
('Sacramento', 'California', 1.7, 5)]
你可以將這個(gè)元組列表傳給DataFrame構(gòu)造器套菜,但還需要列名(位于光標(biāo)的description屬性中):
In [133]: cursor.description
Out[133]:
(('a', None, None, None, None, None, None),
('b', None, None, None, None, None, None),
('c', None, None, None, None, None, None),
('d', None, None, None, None, None, None))
In [134]: pd.DataFrame(rows, columns=[x[0] for x in cursor.description])
Out[134]:
a b c d
0 Atlanta Georgia 1.25 6
1 Tallahassee Florida 2.60 3
2 Sacramento California 1.70 5
這種數(shù)據(jù)規(guī)整操作相當(dāng)多亲善,你肯定不想每查一次數(shù)據(jù)庫就重寫一次。SQLAlchemy項(xiàng)目是一個(gè)流行的Python SQL工具逗柴,它抽象出了SQL數(shù)據(jù)庫中的許多常見差異蛹头。pandas有一個(gè)read_sql函數(shù),可以讓你輕松的從SQLAlchemy連接讀取數(shù)據(jù)。這里渣蜗,我們用SQLAlchemy連接SQLite數(shù)據(jù)庫屠尊,并從之前創(chuàng)建的表讀取數(shù)據(jù):
In [135]: import sqlalchemy as sqla
In [136]: db = sqla.create_engine('sqlite:///mydata.sqlite')
In [137]: pd.read_sql('select * from test', db)
Out[137]:
a b c d
0 Atlanta Georgia 1.25 6
1 Tallahassee Florida 2.60 3
2 Sacramento California 1.70 5
文章代碼引用自:《利用Python進(jìn)行數(shù)據(jù)分析·第2版》第6章 數(shù)據(jù)加載、存儲(chǔ)與文件格式
作者:SeanCheney
感謝SeanCheney同意引用袍睡。