資料載入、儲存及檔案格式
訪問資料是使用各類工具所必需的第一步。我們將重點關注使用pandas進行資料輸入和輸出,儘管其他庫中有許多工具可幫助讀取和寫入各種格式的資料。
輸入和輸出通常有以下幾種型別:讀取文字檔案及硬碟上其他更高效的格式檔案、從資料庫載入資料、與網路資源進行互動(比如Web API)。
1.1文字格式資料的讀寫
將表格型資料讀取為DataFrame物件是pandas的重要特性。
表1-1:Pandas的解析函式
函式 | 描述 |
---|---|
read_csv | 從檔案、URL或檔案型物件讀取分隔好的資料,逗號是預設分隔符 |
read_table | 從檔案、URL或檔案型物件讀取分隔好的資料,製表符(‘\t’)是預設分隔符 |
read_excel | 從Excel的XLS或XLSX檔案中讀取表格資料 |
read_html | 從HTML檔案中讀取所有表格資料 |
read_json | 從JSON字串中讀取資料 |
read_sas | 讀取儲存在SAS系統中定製儲存格式的SAS資料集 |
read_sql | 將SQL查詢的結果讀取為pandas的DataFrame |
一些資料載入函式,比如pandas.read_csv,會進行型別判斷,因為列的資料型別並不是資料格式的一部分。那就意味著我們不必指定哪一列是數值、整數、布林值或字串。
讓我們從一個小型的逗號分隔文字檔案(CSV)開始:
examples.csv
a,b,c,d,message
1,2,3,4,hello
5,6,7,8,world
9,10,11,12,foo
由於這個檔案是逗號分隔的,我們可以使用read_csv將它讀入一個DataFrame:
import pandas as pd df = pd.read_csv('examples.csv') print(df) ------------------------ 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,並指定分隔符:
df = pd.read_table('examples.csv',sep = ',')
print(df)
------------------------
a b c d message
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo
有的檔案不包含表投行。考慮以下檔案:
examples1.csv
1,2,3,4,hello
5,6,7,8,world
9,10,11,12,foo
我們可以允許pandas自動分配預設列名,也可以自己指定列名:
df = pd.read_csv('examples1.csv',header = None)
print(df)
-----------------------
0 1 2 3 4
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo
df = pd.read_csv('examples1.csv',names = ['a','b','c','d','message'])
print(df)
------------------------
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的索引,我們可以這樣操作:
names = ['a','b','c','d','message']
df = pd.read_csv('examples1.csv',names = names,index_col = 'message')
print(df)
----------------------
a b c d
message
hello 1 2 3 4
world 5 6 7 8
foo 9 10 11 12
當你想要從多個列中形成一個分層索引,需要傳入一個包含列序號或列名的列表:
examples2.csv
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
parsed = pd.read_csv('examples2.csv',index_col = ['key1','key2'])
print(parsed)
-------------------------
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傳入一個正則表示式作為分隔符。
解析函式有很多附加引數幫助我們來處理髮生異常的檔案格式,例如,我們可以使用skiprows來跳過第一行、第三行和第四行:
examples3.csv
嘿!
a,b,c,d,message
只是為了讓你覺得更難
誰用計算機讀取CSV檔案?
1,2,3,4,hello
5,6,7,8,world
9,10,11,12,foo
df = pd.read_csv('examples3.csv',skiprows = [0,2,3])
print(df)
------------------------
a b c d message
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo
缺失值處理是檔案解析過程中一個重要的部分。通常情況下,缺失值要麼不顯示(空字串),要麼用一些標識值。預設情況下,pandas使用一些常見的標識,例如NA和NULL:
examples4.csv
something,a,b,c,d,message
one,1,2,3,4,NA
two,5,6,8,world
three,9,10,11,12,foo
result = pd.read_csv('examples4.csv')
print(result)
------------------------------------
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
print(pd.isnull(result))
-------------------------------------------------
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選項可以傳入一個列表或一組字串來處理缺失值:
sentinels = {'message':['foo'],'something':['two']}
print(pd.read_csv('examples4.csv',na_values = sentinels))
------------------------------------
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
表1-1:一些read_csv/read_table函式引數
引數 | 描述 |
---|---|
path | 表明檔案系統位置的字串、URL或檔案型物件 |
sep或delimeter | 用於分隔每行欄位的字串序列或正則表示式 |
header | 用作列名的行號,預設是0(第一行),如果沒有列名的話,應該是None |
index_col | 用作結果中行索引的列號或者列名,可以是單一的名稱/數字,也可以是一個分層索引 |
names | 結果的列名列表,和header=None一起用 |
skiprows | 從檔案開頭處起,需要跳過的行數或行號列表 |
na_values | 需要用NA替換的值序列 |
nrows | 從檔案開頭處讀入的行數 |
encoding | Unicode文字編碼 |
chunksize | 用於迭代的塊大小 |
1.1.1將資料寫入文字格式
資料可以匯出為分隔的形式。讓我們看下之前讀取的CSV檔案:
result = pd.read_csv('examples4.csv')
print(result)
------------------------------------
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方法,我們可以將資料匯出為逗號分隔的檔案:
result.to_csv('examples5.csv')
examples5.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
當然,其他的分隔符也是可以的(寫入到sys.stdout時,控制檯中列印的文字結果):
import sys
result.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
缺失值在輸出時以空字串出現。我們也可以用其他標識值對缺失值進行標註:
result.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
如果沒有其他選項被指定的話,行和列標籤都會被寫入。不過二者也都可以禁止寫入:
result.to_csv('sys.stdout',header = False,index = False)
one,1,2,3.0,4,
two,5,6,8,world
three,9,10,11.0,12,foo
我們也可以僅僅寫入列的子集,並且按照我們所選擇的順序寫入:
result.to_csv('sys.stdout',columns = ['a','b','c'],index = False)
a,b,c
1,2,3.0
5,6,
9,10,11.0
1.1.2使用分割形式
絕大多數的表型資料都可以使用函式pandas.read_table從硬碟中讀取。然而,某些情況下,一些手動操作可能是必不可少的。接收一個帶有一行或多行錯誤的檔案並不少見,read_table也無法解決這種情況。為了介紹一些基礎工具,考慮如下的小型CSV檔案:
examples6.csv
“a”,“b”,“c”
“1”,“2”,“3”
“1”,“2”,“3”
對於任何帶有單字元分隔符的檔案,我們可以使用python的內建csv模組。要使用它,需要將任一開啟的檔案或檔案型物件傳給csv.reader:
import csv
f = open('examples6.csv')
reader = csv.reader(f)
像遍歷檔案那樣遍歷reader會產生元祖,元祖的值為刪除了引號的字元:
for line in reader:
print(line)
---------------
['a', 'b', 'c']
['1', '2', '3']
['1', '2', '3']
隨後我們按部就班,首先將檔案讀取為行的列表:
with open('examples6.csv') as f:
lines = list(csv.reader(f))
然後,我們將資料拆分為列名行和資料行:
header,values = lines[0],lines[1:]
再然後,我們使用字典推導式和表示式zip(*values)生成一個包含資料列的字典,字典中行轉置成列:
data_dict = {h:v for h,v in zip(header,zip(*values))}
print(data_dict)
---------------------------------------------------
{'a': ('1', '1'), 'b': ('2', '2'), 'c': ('3', '3')}