pandas庫之讀寫文本格式的數(shù)據(jù)

pandas提供了一些用于將表格型數(shù)據(jù)讀取為DataFrame對(duì)象的函數(shù)鳞溉。表6-1對(duì)它們進(jìn)行了總結(jié)峻堰,其中read_csv和read_table可能會(huì)是你今后用得最多的。


表6-1 pandas中的解析函數(shù)

我將大致介紹一下這些函數(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)用程序的效率。

什么是CPU密集型减细、IO密集型匆瓜?

注意: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同意引用袍睡。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末知染,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子斑胜,更是在濱河造成了極大的恐慌,老刑警劉巖嫌吠,帶你破解...
    沈念sama閱讀 218,640評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件止潘,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡辫诅,警方通過查閱死者的電腦和手機(jī)凭戴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來炕矮,“玉大人么夫,你說我怎么就攤上這事》羰樱” “怎么了档痪?”我有些...
    開封第一講書人閱讀 165,011評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)邢滑。 經(jīng)常有香客問我腐螟,道長(zhǎng),這世上最難降的妖魔是什么困后? 我笑而不...
    開封第一講書人閱讀 58,755評(píng)論 1 294
  • 正文 為了忘掉前任乐纸,我火速辦了婚禮,結(jié)果婚禮上摇予,老公的妹妹穿的比我還像新娘汽绢。我一直安慰自己,他們只是感情好侧戴,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,774評(píng)論 6 392
  • 文/花漫 我一把揭開白布宁昭。 她就那樣靜靜地躺著,像睡著了一般救鲤。 火紅的嫁衣襯著肌膚如雪久窟。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,610評(píng)論 1 305
  • 那天本缠,我揣著相機(jī)與錄音斥扛,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛稀颁,可吹牛的內(nèi)容都是我干的芬失。 我是一名探鬼主播,決...
    沈念sama閱讀 40,352評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼匾灶,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼棱烂!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起阶女,我...
    開封第一講書人閱讀 39,257評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤颊糜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后秃踩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體衬鱼,經(jīng)...
    沈念sama閱讀 45,717評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,894評(píng)論 3 336
  • 正文 我和宋清朗相戀三年憔杨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鸟赫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,021評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡消别,死狀恐怖抛蚤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情寻狂,我是刑警寧澤岁经,帶...
    沈念sama閱讀 35,735評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站荆虱,受9級(jí)特大地震影響蒿偎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜怀读,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,354評(píng)論 3 330
  • 文/蒙蒙 一诉位、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧菜枷,春花似錦苍糠、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蚊锹,卻和暖如春瞳筏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背牡昆。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工姚炕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,224評(píng)論 3 371
  • 正文 我出身青樓柱宦,卻偏偏與公主長(zhǎng)得像些椒,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子掸刊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,974評(píng)論 2 355