標籤:

利用python進行數據分析之數據載入、存儲與文件格式(五)

書中源碼與數據集 github.com/pydata/pydat

目錄

6.1 讀寫文件格式的數據

6.2 二進位數據格式

6.3 使用 html 和web API

6.4 使用資料庫

輸入和輸出可以劃分幾個大類:讀取文本文件和其他更高效的磁碟存儲格式,載入資料庫中的數據,利用web API操作網路資源。

6.1 讀寫文件格式的數據

pandas中得解析函數

函數

read_csvt 從文件、URL、文件型對象中載入帶分隔符的數據。默認分隔符為逗號

read_table 從文件、URL、文件型對象中載入帶分隔符的數據。默認分隔符為製表符("t")

reda_fwft 讀取定寬格式數據(沒有分隔符)

read_clipboard 讀取剪貼板中的數據,可以看做read_table的剪貼板版。在將網頁轉換為表格時很有用

這些函數的選項可以劃分下面幾大類:

  • 索引:將一個或多個列當做返回的DataFrame處理,以及是否從文件、用戶獲得列名
  • 類型推斷和數據轉換:包括用戶定義值得轉換、缺失值標記列表等
  • 日期解析:包括組合功能,比如將分散在多個列中的日期時間信息組合成結果中的單個列。
  • 迭代:支持對大文件進行逐塊迭代
  • 不規整數據問題:跳過一些行、頁腳、注釋或其他一些不重要的東西(比如成千上萬個逗號隔開的數值數據)

類型推斷是這些函數中最重要的功能之一。我們不需要知道列的類型到底是數值、整數、布爾值、還是字元串。

我們給出一個以逗號分隔的(CSV)文件:

我們使用type的這個Window shell命令將文本的原始內容列印到屏幕上。

In [22]: !type E:ch06ex1.csvna,b,c,d,messagen1,2,3,4,hellon5,6,7,8,worldn9,10,11,12,foon

由於文件以逗號分隔,所以我們可以使用read_csv將其讀入一個DataFrame:

In [25]: df=pd.read_csv(E:ch06ex1.csv)nnIn [26]: dfnOut[26]:na b c d messagen0 1 2 3 4 hellon1 5 6 7 8 worldn2 9 10 11 12 foon

還可以使用read_table ,這時需要指定分隔符:

In [28]: pd.read_table(E:ch06ex1.csv,sep=,)nOut[28]:na b c d messagen0 1 2 3 4 hellon1 5 6 7 8 worldn2 9 10 11 12 foon

假如不指定分隔符:

In [29]: pd.read_table(E:ch06ex1.csv)nOut[29]:na,b,c,d,messagen0 1,2,3,4,hellon1 5,6,7,8,worldn2 9,10,11,12,foon

並不是所有的文件本身就有標題行。我們可以自己分配默認的列名,也可以自己定義列名:

In [3]: !type E:ch06ex2.csvn1,2,3,4,hellon5,6,7,8,worldn9,10,11,12,foonnIn [5]: pd.read_csv(E:ch06ex2.csv,header=None)nOut[5]:n0 1 2 3 4n0 1 2 3 4 hellon1 5 6 7 8 worldn2 9 10 11 12 foonnIn [8]: pd.read_csv(E:ch06ex2.csv,names=[a,b,c,d,message])nOut[8]:na b c d messagen0 1 2 3 4 hellon1 5 6 7 8 worldn2 9 10 11 12 foon

假如我們希望將message列作為DataFrame的索引,我們可以明確表示要將該列放在索引4的位置上,也可以通過index_col參數指定「message」 :

In [10]: names=[a,b,c,d,message]nnIn [11]: pd.read_csv(E:ch06ex2.csv,names=names,index_col=message)nOut[11]:na b c dnmessagenhello 1 2 3 4nworld 5 6 7 8nfoo 9 10 11 12n

如果我們希望將多個列做成一個層次化索引,只需要傳入編號或列名組成的列表即可:

In [15]: !type E:ch06_mindex.csvnkey1,key2,value1,value2none,a,1,2none,b,3,4none,c,5,6none,d,7,8ntwo,a,9,10ntwo,b,11,12ntwo,c,13,14ntwo,d,15,16nnIn [17]: parsed=pd.read_csv(E:ch06_mindex.csv,index_col=[key1,key2])nnIn [18]: parsednOut[18]:nvalue1 value2nkey1 key2none a 1 2nb 3 4nc 5 6nd 7 8ntwo a 9 10nb 11 12nc 13 14nd 15 16n

有些表格可能不是用固定的分隔符去分隔欄位的,對於這種情況,我們編寫一個正則表達式來作為 read_table的分隔符。

In [35]: list(open(E:ch06ex3.txt))nOut[35]:n[ A B Cn,naaa -0.264438 -1.343465 -0.619500n,nbbb -0.264438 -1.343465 -0.619500n,nccc -0.264438 -1.343465 -0.619500n,nddd -0.264438 -1.343465 -0.619500n]n

該文件各個欄位由數量不定的空白字元分隔。我們可以使用正則表達式s+ 表示,

In [36]: result=pd.read_table(E:ch06ex3.txt,sep=s+)nnIn [37]: resultnOut[37]:nA B Cnaaa -0.264438 -1.343465 -0.6195nbbb -0.264438 -1.343465 -0.6195nccc -0.264438 -1.343465 -0.6195nddd -0.264438 -1.343465 -0.6195n

上面由於列名比數據行的數量少,索引read_table推斷第一列應該是DataFrame的索引。

許多解析器函數的許多參數可以幫助你處理各種各樣的異形文件格式。比如,用skiprows跳過文件的第一行、第三行、第四行。

In [4]: !type E:ch06ex4.csvn#hey!na,b,c,d,messagen#just wanted to make things more difficult for youn#who reads CSV files with computers,anyway?n1,2,3,4,hellon5,6,7,8,worldn9,10,11,12,foonnIn [5]: pd.read_csv(E:ch06ex4.csv,skiprows=[0,2,3])nOut[5]:na b c d messagen0 1 2 3 4 hellon1 5 6 7 8 worldn2 9 10 11 12 foon

缺失值處理是文件解析任務重要組成。缺失數據會沒有空字元串,或者某個標記值表示。

默認下,pandas會用一組常出現的標記值進行識別,如NA,-1.#IND以及NULL等:

In [56]: !type E:ch06ex5.csvnsomething,a,b,c,d,messagenone,1,2,3,4,NAntwo,5,6,,8,worldnthree,9,10,11,12,foonnIn [58]: import pandas as pdnnIn [59]: result=pd.read_csv(E:ch06ex5.csv)nnIn [60]: resultnOut[60]:nsomething a b c d messagen0 one 1 2 3.0 4 NaNn1 two 5 6 NaN 8 worldn2 three 9 10 11.0 12 foonnIn [61]: pd.isnull(result)nOut[61]:nsomething a b c d messagen0 False False False False False Truen1 False False False True False Falsen2 False False False False False Falsen

na_values可以接受一組用於表示缺失值的字元串:

In [62]: result=pd.read_csv(E:ch06ex5.csv,na_values=[NULL])nnIn [63]: resultnOut[63]:nsomething a b c d messagen0 one 1 2 3.0 4 NaNn1 two 5 6 NaN 8 worldn2 three 9 10 11.0 12 foon

可以用一個字典為各列指定不同的NA標記值:

In [65]: sentinels={message:[foo,NA],something:[two]}nnIn [66]: result=pd.read_csv(E:ch06ex5.csv,na_values=sentinels)nnIn [67]: resultnOut[67]:nsomething a b c d messagen0 one 1 2 3.0 4 NaNn1 NaN 5 6 NaN 8 worldn2 three 9 10 11.0 12 NaNn

6.1 .1 逐塊讀取文件文件

處理大文件時候,我們可能需要文件的一小部分,或者逐塊對文件進行迭代:

In [4]: result=pd.read_csv(rF:pydata-book-masterch06ex6.csv)nnIn [5]: resultnOut[5]: n one two three four keyn0 0.467976 -0.038649 -0.295344 -1.824726 Ln1 -0.358893 1.404453 0.704965 -0.200638 Bn2 -0.501840 0.659254 -0.421691 -0.057688 Gn3 0.204886 1.074134 1.388361 -0.982404 Rn4 0.354628 -0.133116 0.283763 -0.837063 Qn5 1.817480 0.742273 0.419395 -2.251035 Qn... ... ... ... ... ..n9993 1.821117 0.416445 0.173874 0.505118 Xn9994 0.068804 1.322759 0.802346 0.223618 Hn9995 2.311896 -0.417070 -1.409599 -0.515821 Ln9996 -0.479893 -0.650419 0.745152 -0.646038 En9997 0.523331 0.787112 0.486066 1.093156 Kn9998 -0.362559 0.598894 -1.843201 0.887292 Gn9999 -0.096376 -1.012999 -0.657431 -0.573315 0nn[10000 rows x 5 columns]n

我們只想讀取幾行的,通過nrows來指定行即可:

In [7]: pd.read_csv(rF:pydata-book-masterch06ex6.csv,nrows=5)nOut[7]: n one two three four keyn0 0.467976 -0.038649 -0.295344 -1.824726 Ln1 -0.358893 1.404453 0.704965 -0.200638 Bn2 -0.501840 0.659254 -0.421691 -0.057688 Gn3 0.204886 1.074134 1.388361 -0.982404 Rn4 0.354628 -0.133116 0.283763 -0.837063 Qn

要逐塊讀取文件,需要設置chunksize (行數):

In [10]: chunker=pd.read_csv(rF:pydata-book-masterch06ex6.csv,chunksize=10000)nnIn [11]: chunkernOut[11]: <pandas.io.parsers.TextFileReader at 0xb894d68>n

read_csv所返回的這個TextParser對象使你可以根據chunksize對文件進行逐塊迭代。

比如我們可以迭代ex6.csv,將值計數聚合到「key」中,

In [10]: chunker=pd.read_csv(rF:pydata-book-masterch06ex6.csv,chunksize=10000)nnIn [11]: chunkernOut[11]: <pandas.io.parsers.TextFileReader at 0xb894d68>nnnIn [13]: from pandas import Series,DataFramennIn [14]: tot=Series([])nnIn [15]: for piece in chunker:n ...: tot=tot.add(piece[key].value_counts(),fill_value=0)n ...:nnIn [16]: tot.order(ascending=False)n__main__:1: FutureWarning: order is deprecated, use sort_values(...)nOut[16]:nE 368.0nX 364.0nL 346.0nO 343.0nQ 340.0nM 338.0nJ 337.0nF 335.0nK 334.0nH 330.0nV 328.0nI 327.0nU 326.0nP 324.0nD 320.0nA 320.0nR 318.0nY 314.0nG 308.0nS 308.0nN 306.0nW 305.0nT 304.0nB 302.0nZ 288.0nC 286.0n4 171.0n6 166.0n7 164.0n3 162.0n8 162.0n5 157.0n2 152.0n0 151.0n9 150.0n1 146.0ndtype: float64nnIn [17]: tot[:6]nOut[17]:nE 368.0nX 364.0nL 346.0nO 343.0nQ 340.0nM 338.0ndtype: float64n

6.1.2 將數據寫出到文本格式

將數據寫出帶文本格式

數據也可以被輸出為分隔符個格式的文本。

我們看看之前讀過的CSV文件。

In [1]: import pandas as pdnnIn [2]: data=pd.read_csv(r"F:pydata-book-masterch06ex5.csv")nnIn [3]: datanOut[3]: n something a b c d messagen0 one 1 2 3.0 4 NaNn1 two 5 6 NaN 8 worldn2 three 9 10 11.0 12 foonnnIn [6]: !type "F:pydata-book-masterch06out.csv"n,something,a,b,c,d,messagen0,one,1,2,3.0,4,n1,two,5,6,,8,worldn2,three,9,10,11.0,12,foon

當然,還可以使用其他分隔符

In [8]: import sysnnIn [9]: data.to_csv(sys.stdout,sep=|)n|something|a|b|c|d|messagen0|one|1|2|3.0|4|n1|two|5|6||8|worldn2|three|9|10|11.0|12|foon

缺失值在輸出結果中會被表示為空字元,可能我們會希望將它表示其他字元

In [10]: data.to_csv(sys.stdout,na_rep="NULL")n,something,a,b,c,d,messagen0,one,1,2,3.0,4,NULLn1,two,5,6,NULL,8,worldn2,three,9,10,11.0,12,foon

沒有其他選項會寫出行和列標籤。

In [11]: data.to_csv(sys.stdout,index=False,header=False)none,1,2,3.0,4,ntwo,5,6,,8,worldnthree,9,10,11.0,12,foon

還可以寫出一部分列,指定以下的順序排列:

Series有一個to_csv的方法,

In [16]: from pandas import Series,DataFramennIn [18]: import numpy as npnnIn [20]: dates=pd.date_range(1/1/2000,periods=7)nnIn [21]: ts=Series(np.arange(7),index=dates)nnIn [22]: ts.to_csv(r"F:pydata-book-masterch06tseries.csv")nnIn [23]: !type F:pydata-book-masterch06tseries.csv"n2000-01-01,0n2000-01-02,1n2000-01-03,2n2000-01-04,3n2000-01-05,4n2000-01-06,5n2000-01-07,6n

我們還有一個from_csv方法:

In [24]: Series.from_csv(rF:pydata-book-masterch06tseries.csv,parse_dates=True)nOut[24]: n2000-01-01 0n2000-01-02 1n2000-01-03 2n2000-01-04 3n2000-01-05 4n2000-01-06 5n2000-01-07 6ndtype: int64n

6.1.3 ·手工處理分隔符格式

大部分表格型數據用到pandas.read_table進行載入。有時候我們需要一些手工處理。

In [25]: !type F:pydata-book-masterch06ex7.csvn"a","b","c"n"1","2","3"n"1","2","3","4"n

對於單字元分隔符文件,可以直接使用python內置的csv模塊。將任意的打開的文件或文件型的對象傳給csv.reader

In [26]: import csvnnIn [27]: f=open(r"F:pydata-book-masterch06ex7.csv")nnIn [28]: reader=csv.reader(f)n

#對這個reader進行迭代將會為每行產生一個元組:

In [30]: for line in reader:n ...: print linen ...: n[a, b, c]n[1, 2, 3]n[1, 2, 3, 4]n

為了使數據格式合乎要求,需要我們整理一下:

In [4]: lines=list(csv.reader(open(F:pydata-book-masterch06ex7.csv)))nnIn [5]: header,values=lines[0],lines[1:]nnIn [8]: header,valuesnOut[8]: ([a, b, c], [[1, 2, 3], [1, 2, 3, 4]])nnIn [9]: data_dict={h:v for h,v in zip(header,zip(*values))}nnIn [10]: header,valuesnOut[10]: ([a, b, c], [[1, 2, 3], [1, 2, 3, 4]])n

csv文件的形式有很多種,只需要定義csv.Dialect的一個子類可定義出新格式(如專門的分隔符、字元串引用約定、行結束符等):

class my_dialect(csv.Dialect):n lineterminator=nn delimiter=;n quotechar= " nreader=csv.reader(f,dialect=my_dialect)n

各個csv語支的參數可以關鍵字的形式提供給csv.reader ,而無需定義子類:

reader=csv.reader(f,delimiter=|)n

注意:對於複雜的分隔符或多字元的分隔符的文件,我們要使用字元串的split方法或正則表達式re.split進行拆分和其他整理工作。

我們在手動的輸出分隔符的文件,可以使用csv.writer

它接收一個已經打開的且可寫的文件對象以及跟csv.reader相同的那些語支和格式化選項:

with open(rF:pydata-book-masterch06mydata.csv,w) as f: n writer=csv.writer(f,dialect=my_dialect)n writer.writerow((one,two,three))n writer.writerow((1,2,3))n writer.writerow((4,5,6))n writer.writerow((7,8,9))n

6.1.4 JSON數據

JSON(JavaScript Object Notation的簡稱)已經成為通過HTTP請求在Web瀏覽器和其他應用程序之間發送數據的標準格式之一。

JSON是一種比表格型文本格式(如CSV)靈活得多的數據格式:

json的本質是字典,是hash表,用來存儲非結構化的數據。

csv本質是表,用來存儲結構化數據

給出一個例子

obj="""{"name":"Wes","places_lived":["United States","Spain","Germany"],"pet":null,"siblings":[{"name":"Scott","age":25,"pet":"Zuko"},{"name":"Katie","age":33,"pet":"Cisco"}]}"""nIn [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"}]}"""n

JSON非常接近有效的python代碼。基本類型有對象(字典),數組(列表),字元串,數值,布爾值,以及null。

對象中的鍵必須是字元串。

In [13]: import jsonnnIn [14]: result=json.loads(obj)nnIn [15]: resultnOut[15]:n{name: Wes,npet: None,nplaces_lived: [United States, Spain, Germany],nsiblings: [{age: 25, name: Scott, pet: Zuko},n{age: 33, name: Katie, pet: Cisco}]}n

相反,json.dump則將python對象轉換為JSON格式:

asjson=json.dumps(result)n

如何將JSON對象轉換為DataFrame 或其他便於分析的數據結構。

最為方便的一個方式:向DataFrame構造器傳入一組JSON對象,並選取數據欄位的子集。

In [29]: siblings=DataFrame(result[siblings],columns=[name,age])nnIn [30]: siblingsnOut[30]:nname agen0 Scott 25n1 Katie 33n

推薦閱讀:

TAG:Python |