書中源碼與數(shù)據(jù)集http://github.com/pydata/pydata-book
目錄
6.1 讀寫文件格式的數(shù)據(jù)
6.2 二進制數(shù)據(jù)格式
6.3 使用 html 和web API
6.4 使用數(shù)據(jù)庫
輸入和輸出可以劃分幾個大類:讀取文本文件和其他更高效的磁盤存儲格式柱告,加載數(shù)據(jù)庫中的數(shù)據(jù),利用web API操作網(wǎng)絡(luò)資源诊县。
6.1 讀寫文件格式的數(shù)據(jù)
pandas中得解析函數(shù)
函數(shù)
read_csv ? ? ? 從文件骡楼、URL、文件型對象中加載帶分隔符的數(shù)據(jù)赴肚。默認(rèn)分隔符為逗號
read_table? ? 從文件华畏、URL、文件型對象中加載帶分隔符的數(shù)據(jù)尊蚁。默認(rèn)分隔符為制表符("\t")
reda_fwf ? ? ? 讀取定寬格式數(shù)據(jù)(沒有分隔符)
read_clipboard? 讀取剪貼板中的數(shù)據(jù)亡笑,可以看做read_table的剪貼板版。在將網(wǎng)頁轉(zhuǎn)換為表格時很有用
這些函數(shù)的選項可以劃分下面幾大類:
索引:將一個或多個列當(dāng)做返回的DataFrame處理横朋,以及是否從文件仑乌、用戶獲得列名
類型推斷和數(shù)據(jù)轉(zhuǎn)換:包括用戶定義值得轉(zhuǎn)換、缺失值標(biāo)記列表等
日期解析:包括組合功能晰甚,比如將分散在多個列中的日期時間信息組合成結(jié)果中的單個列决帖。
迭代:支持對大文件進行逐塊迭代
不規(guī)整數(shù)據(jù)問題:跳過一些行、頁腳地回、注釋或其他一些不重要的東西(比如成千上萬個逗號隔開的數(shù)值數(shù)據(jù))
類型推斷是這些函數(shù)中最重要的功能之一扁远。我們不需要知道列的類型到底是數(shù)值刻像、整數(shù)、布爾值细睡、還是字符串谷羞。
我們給出一個以逗號分隔的(CSV)文件:
我們使用type的這個Window shell命令將文本的原始內(nèi)容打印到屏幕上。
In [22]:!type E:\\ch06ex1.csv
a,b,c,d,message
1,2,3,4,hello
5,6,7,8,world
9,10,11,12,foo
由于文件以逗號分隔溜徙,所以我們可以使用read_csv將其讀入一個DataFrame:
In [25]:df=pd.read_csv('E:\\ch06ex1.csv')
In [26]:df
Out[26]:
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 [28]:pd.read_table('E:\\ch06ex1.csv',sep=',')
Out[28]:
a b c d message
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo
假如不指定分隔符:
In [29]:pd.read_table('E:\\ch06ex1.csv')
Out[29]:
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)題行。我們可以自己分配默認(rèn)的列名靠瞎,也可以自己定義列名:
In [3]:!type E:\\ch06ex2.csv
1,2,3,4,hello
5,6,7,8,world
9,10,11,12,foo
In [5]:pd.read_csv('E:\\ch06ex2.csv',header=None)
Out[5]:
0 1 2 3 4
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo
In [8]:pd.read_csv('E:\\ch06ex2.csv',names=['a','b','c','d','message'])
Out[8]:
a b c d message
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo
假如我們希望將message列作為DataFrame的索引求妹,我們可以明確表示要將該列放在索引4的位置上,也可以通過index_col參數(shù)指定“message” :
In [10]:names=['a','b','c','d','message']
In [11]:pd.read_csv('E:\\ch06ex2.csv',names=names,index_col='message')
Out[11]:
a b c d
message
hello 1 2 3 4
world 5 6 7 8
foo 9 10 11 12
如果我們希望將多個列做成一個層次化索引父能,只需要傳入編號或列名組成的列表即可:
In [15]:!type E:\\ch06_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 [17]:parsed=pd.read_csv('E:\\ch06_mindex.csv',index_col=['key1','key2'])
In [18]:parsed
Out[18]:
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
有些表格可能不是用固定的分隔符去分隔字段的何吝,對于這種情況鹃唯,我們編寫一個正則表達式來作為 read_table的分隔符。
In [35]:list(open('E:\\ch06ex3.txt'))
Out[35]:
[' A B C\n',
'aaa -0.264438 -1.343465 -0.619500\n',
'bbb -0.264438 -1.343465 -0.619500\n',
'ccc -0.264438 -1.343465 -0.619500\n',
'ddd -0.264438 -1.343465 -0.619500\n']
該文件各個字段由數(shù)量不定的空白字符分隔黔酥。我們可以使用正則表達式\s+ 表示跪者,
In [36]:result=pd.read_table('E:\\ch06ex3.txt',sep='\s+')
In [37]:result
Out[37]:
A B C
aaa -0.264438 -1.343465 -0.6195
bbb -0.264438 -1.343465 -0.6195
ccc? -0.264438 -1.343465 -0.6195
ddd? -0.264438 -1.343465 -0.6195
上面由于列名比數(shù)據(jù)行的數(shù)量少熄求,索引read_table推斷第一列應(yīng)該是DataFrame的索引。
許多解析器函數(shù)的許多參數(shù)可以幫助你處理各種各樣的異形文件格式忘衍。比如卿城,用skiprows跳過文件的第一行、第三行秘噪、第四行勉耀。
In [4]:!type E:\\ch06ex4.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 [5]:pd.read_csv('E:\\ch06ex4.csv',skiprows=[0,2,3])
Out[5]:
a b c d message
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo
缺失值處理是文件解析任務(wù)重要組成便斥。缺失數(shù)據(jù)會沒有空字符串,或者某個標(biāo)記值表示像街。
默認(rèn)下,pandas會用一組常出現(xiàn)的標(biāo)記值進行識別脓斩,如NA畴栖,-1.#IND以及NULL等:
In [56]:!type E:\\ch06ex5.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 [58]:import pandas as pd
In [59]:result=pd.read_csv('E:\\ch06ex5.csv')
In [60]:result
Out[60]:
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 [61]:pd.isnull(result)
Out[61]:
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可以接受一組用于表示缺失值的字符串:
In [62]:result=pd.read_csv('E:\\ch06ex5.csv',na_values=['NULL'])
In [63]:result
Out[63]:
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
可以用一個字典為各列指定不同的NA標(biāo)記值:
In [65]:sentinels={'message':['foo','NA'],'something':['two']}
In [66]:result=pd.read_csv('E:\\ch06ex5.csv',na_values=sentinels)
In [67]:result
Out[67]:
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.1 .1 逐塊讀取文件文件
處理大文件時候吗讶,我們可能需要文件的一小部分照皆,或者逐塊對文件進行迭代:
In [4]: result=pd.read_csv(r'F:\pydata-book-master\ch06\ex6.csv')
In [5]: result
Out[5]:
one? ? ? two? ? three? ? ? four key
00.467976-0.038649-0.295344-1.824726L
1? ? -0.3588931.4044530.704965-0.200638B
2? ? -0.5018400.659254-0.421691-0.057688G
30.2048861.0741341.388361-0.982404R
40.354628-0.1331160.283763-0.837063Q
51.8174800.7422730.419395-2.251035Q
...? ? ? ? ...? ? ? ...? ? ? ...? ? ? ...? ..
99931.8211170.4164450.1738740.505118X
99940.0688041.3227590.8023460.223618H
99952.311896-0.417070-1.409599-0.515821L
9996 -0.479893-0.6504190.745152-0.646038E
99970.5233310.7871120.4860661.093156K
9998 -0.3625590.598894-1.8432010.887292G
9999 -0.096376-1.012999-0.657431-0.5733150
[10000 rows x 5 columns]
我們只想讀取幾行的,通過nrows來指定行即可:
In [7]: pd.read_csv(r'F:\pydata-book-master\ch06\ex6.csv',nrows=5)
Out[7]:
one? ? ? two? ? three? ? ? four key
00.467976-0.038649-0.295344-1.824726L
1 -0.3588931.4044530.704965-0.200638B
2 -0.5018400.659254-0.421691-0.057688G
30.2048861.0741341.388361-0.982404R
40.354628-0.1331160.283763-0.837063Q
要逐塊讀取文件论寨,需要設(shè)置chunksize (行數(shù)):
In [10]:chunker=pd.read_csv(r'F:\pydata-book-master\ch06\ex6.csv',chunksize=10000)
In [11]:chunker
Out[11]:
read_csv所返回的這個TextParser對象使你可以根據(jù)chunksize對文件進行逐塊迭代葬凳。
比如我們可以迭代ex6.csv室奏,將值計數(shù)聚合到“key”中,
In [10]:chunker=pd.read_csv(r'F:\pydata-book-master\ch06\ex6.csv',chunksize=10000)
In [11]:chunker
Out[11]:
In [13]:from pandas import Series,DataFrame
In [14]:tot=Series([])
In [15]:for piece in chunker:
...:tot=tot.add(piece['key'].value_counts(),fill_value=0)
...:
In [16]:tot.order(ascending=False)
__main__:1: FutureWarning: order is deprecated, use sort_values(...)
Out[16]:
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
V 328.0
I 327.0
U 326.0
P 324.0
D 320.0
A 320.0
R 318.0
Y 314.0
G 308.0
S 308.0
N 306.0
W 305.0
T 304.0
B 302.0
Z 288.0
C 286.0
4 171.0
6 166.0
7 164.0
3 162.0
8 162.0
5 157.0
2 152.0
0 151.0
9 150.0
1 146.0
dtype: float64
In [17]:tot[:6]
Out[17]:
E 368.0
X 364.0
L 346.0
O 343.0
Q 340.0
M 338.0
dtype: float64
6.1.2 將數(shù)據(jù)寫出到文本格式
將數(shù)據(jù)寫出帶文本格式
數(shù)據(jù)也可以被輸出為分隔符個格式的文本。
我們看看之前讀過的CSV文件绒怨。
In [1]: import pandas as pd
In [2]: data=pd.read_csv(r"F:\pydata-book-master\ch06\ex5.csv")
In [3]: data
Out[3]:
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 [6]: !type "F:\pydata-book-master\ch06\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)然南蹂,還可以使用其他分隔符
In [8]: import sys
In [9]: 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
缺失值在輸出結(jié)果中會被表示為空字符,可能我們會希望將它表示其他字符
In [10]: 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
沒有其他選項會寫出行和列標(biāo)簽晚顷。
In [11]: 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
還可以寫出一部分列疗疟,指定以下的順序排列:
Series有一個to_csv的方法策彤,
In [16]: from pandas import Series,DataFrame
In [18]: import numpy as np
In [20]: dates=pd.date_range('1/1/2000',periods=7)
In [21]: ts=Series(np.arange(7),index=dates)
In [22]: ts.to_csv(r"F:\pydata-book-master\ch06\tseries.csv")
In [23]: !type F:\pydata-book-master\ch06\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
我們還有一個from_csv方法:
In [24]: Series.from_csv(r'F:\pydata-book-master\ch06\tseries.csv',parse_dates=True)
Out[24]:
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
dtype: int64
6.1.3 ·手工處理分隔符格式
大部分表格型數(shù)據(jù)用到pandas.read_table進行加載匣摘。有時候我們需要一些手工處理音榜。
In [25]: !type F:\pydata-book-master\ch06\ex7.csv
"a","b","c"
"1","2","3"
"1","2","3","4"
對于單字符分隔符文件必指,可以直接使用python內(nèi)置的csv模塊恕洲。將任意的打開的文件或文件型的對象傳給csv.reader
In [26]: import csv
In [27]: f=open(r"F:\pydata-book-master\ch06\ex7.csv")
In [28]: reader=csv.reader(f)
#對這個reader進行迭代將會為每行產(chǎn)生一個元組:
In [30]: for line in reader:
...:? ? print line
...:
['a', 'b', 'c']
['1', '2', '3']
['1', '2', '3', '4']
為了使數(shù)據(jù)格式合乎要求霜第,需要我們整理一下:
In [4]:lines=list(csv.reader(open('F:\pydata-book-master\ch06\ex7.csv')))
In [5]:header,values=lines[0],lines[1:]
In [8]:header,values
Out[8]:(['a', 'b', 'c'], [['1', '2', '3'], ['1', '2', '3', '4']])
In [9]:data_dict={h:v for h,v in zip(header,zip(*values))}
In [10]:header,values
Out[10]:(['a', 'b', 'c'], [['1', '2', '3'], ['1', '2', '3', '4']])
csv文件的形式有很多種,只需要定義csv.Dialect的一個子類可定義出新格式(如專門的分隔符癞谒、字符串引用約定刃榨、行結(jié)束符等):
In [22]:class my_dialect(csv.Dialect):
...:lineterminator='\n'
...:delimiter=';'
...:quotechar='"'
...:
In [25]:f=open(r"E:\pydata-book-master\pydata-book-master\ch06\ex7.csv")
In [26]:reader = csv.reader(f, dialect=my_dialect, quoting = csv.QUOTE_ALL)
In [27]:reader
Out[27]:<_csv.reader at 0x245b0168>
各個csv語支的參數(shù)可以關(guān)鍵字的形式提供給csv.reader 枢希,而無需定義子類:
reader=csv.reader(f,delimiter='|')
注意:對于復(fù)雜的分隔符或多字符的分隔符的文件,我們要使用字符串的split方法或正則表達式re.split進行拆分和其他整理工作茅诱。
我們在手動的輸出分隔符的文件搬卒,可以使用csv.writer
它接收一個已經(jīng)打開的且可寫的文件對象以及跟csv.reader相同的那些語支和格式化選項:
In [30]:with open(r'E:\pydata-book-master\pydata-book-master\ch06\mydata.csv','w') as f:
...:writer=csv.writer(f,dialect=my_dialect,quoting = csv.QUOTE_ALL)
...:writer.writerow(('one','two','three'))
...:writer.writerow(('1','2','3'))
...:writer.writerow(('4','5','6'))
...:writer.writerow(('7','8','9'))
6.1.4 JSON數(shù)據(jù)
JSON(JavaScript Object Notation的簡稱)已經(jīng)成為通過HTTP請求在Web瀏覽器和其他應(yīng)用程序之間發(fā)送數(shù)據(jù)的標(biāo)準(zhǔn)格式之一契邀。
JSON是一種比表格型文本格式(如CSV)靈活得多的數(shù)據(jù)格式:
json的本質(zhì)是字典,是hash表椭迎,用來存儲非結(jié)構(gòu)化的數(shù)據(jù)田盈。
csv本質(zhì)是表,用來存儲結(jié)構(gòu)化數(shù)據(jù)
給出一個例子
obj="""{"name":"Wes","places_lived":["United States","Spain","Germany"],"pet":null,"siblings":[{"name":"Scott","age":25,"pet":"Zuko"},{"name":"Katie","age":33,"pet":"Cisco"}]}"""
In [12]:obj="""{"name":"Wes","places_lived":["United States","Spain","Germany"],"pet":null,"siblings":[{"name":"Scott","age":25,"pet":"Zuko"},{"name":"Katie","age":33,"pet":"Cisco"}]}"""
JSON非常接近有效的python代碼简软。基本類型有對象(字典)建炫,數(shù)組(列表)疼蛾,字符串察郁,數(shù)值,布爾值稳捆,以及null麦轰。
對象中的鍵必須是字符串。
In [13]:import json
In [14]:result=json.loads(obj)
In [15]:result
Out[15]:
{'name': 'Wes',
'pet': None,
'places_lived': ['United States', 'Spain', 'Germany'],
'siblings': [{'age': 25, 'name': 'Scott', 'pet': 'Zuko'},
{'age': 33, 'name': 'Katie', 'pet': 'Cisco'}]}
相反末荐,json.dump則將python對象轉(zhuǎn)換為JSON格式:
asjson=json.dumps(result)
如何將JSON對象轉(zhuǎn)換為DataFrame 或其他便于分析的數(shù)據(jù)結(jié)構(gòu)新锈。
最為方便的一個方式:向DataFrame構(gòu)造器傳入一組JSON對象壕鹉,并選取數(shù)據(jù)字段的子集。
In [29]:siblings=DataFrame(result['siblings'],columns=['name','age'])
In [30]:siblings
Out[30]:
name age
0 Scott 25
1 Katie 33
6.1.5 XML和HTML:Web信息收集
python中有許多可以讀寫HTML和XML格式數(shù)據(jù)的庫负乡,lxml就是其中之一脊凰,它能夠高效的解析大文件。lxml有多編程接口切省,首先要要用lxml.html處理HTML帕胆,然后在用lxml.objetify做一些XML處理。
In [31]:from lxml.html import parse
In [32]:from urllib2 import urlopen
In [33]:parsed=parse(urlopen=('http://finance.yahoo.com/q/op?s=AAPL+Options'))
Traceback(most recent call last):
File"", line1, in
parsed=parse(urlopen=('http://finance.yahoo.com/q/op?s=AAPL+Options'))
TypeError:parse() takes at least 1 argument (0 given)
6.1.5.1 利用lxml.objectify 解析XML
XML(extensible markup language)是另一種常見的支持分層芙盘、嵌套數(shù)據(jù)以及元數(shù)據(jù)的結(jié)構(gòu)化數(shù)據(jù)格式儒老。
6.2 二進制數(shù)據(jù)格式
實現(xiàn)數(shù)據(jù)的二進制格式的存儲的最簡單的辦法之一就是使用python內(nèi)置的pickle序列化。為了使用方便薇正,pandas 對象都有一個將數(shù)據(jù)以pickle形式保存到磁盤上的save的方法囚衔;
6.3 使用 html 和web API
6.4 使用數(shù)據(jù)庫