1. 程式人生 > >資料載入、儲存及檔案格式

資料載入、儲存及檔案格式

訪問資料是使用各類工具所必需的第一步。我們將重點關注使用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')}