博客 / 詳情

返回

利用 Python 進行數據分析 —— 4 數據的導入導出

在數據分析中,我們一般不會像前幾篇文章那樣自己創造數據,而是需要利用外部數據。本篇要解決兩個問題:

  • 如何將外部數據導入,並轉換為 DataFrame?
  • 如何將 DataFrame 導出為常用的文件格式?

4.1 讀取文本數據

本篇文章用到的數據,可以從 GitHub 上下載:https://github.com/wesm/pydat...

4.1.1 csv 數據:處理標題行

我們可以從 csv 數據入手,看看如何將 csv 數據導入為 DataFrame:

 in: df = pd.read_csv('examples\ex1.csv')  
     df
out:    a   b   c   d message
     0  1   2   3   4   hello
     1  5   6   7   8   world
     2  9  10  11  12     foo

如果你用的是 PyCharm IDE 的話,看看 Console 中的變量部分,變量 “df” 的右邊會有一個 “view as DataFrame” 的按鈕。點擊它,你可以看到這樣的視圖:

view as DataFrame.jpg

這個視圖在數據量很大的時候很有用,能幫你粗略地檢視數據。

除了 pd.read_csv() 外,pandas 還提供了讀取其他形式數據的方法,如 pd.read_table(), pd. read_json(), pd.read_excel() 等。

pd.read_table('examples\ex1.csv', sep=',')  # 由於 pd.read_table() 的默認分隔符是 tab,我們需要手動指定一下,以打開我們的文件

如果文件沒有標題行(字段名/列名),該怎麼做?

 in: pd.read_csv('examples\ex2.csv')
out:    1   2   3   4  hello  # 可以看到,pandas 默認認為第一行是標題行,這和我們想要的結果不符
     0  5   6   7   8  world 
     1  9  10  11  12    foo
 
 in: pd.read_csv('examples\ex2.csv', header=None)  # 這樣就可以讓 pandas 不把第一行視為標題行
out:    0   1   2   3      4  # pandas 默認生成了一行連續數作為標題行
     0  1   2   3   4  hello
     1  5   6   7   8  world
     2  9  10  11  12    foo
 
 in: pd.read_csv('examples\ex2.csv', names=['a','b','c','d','message'])  # 可以像這樣給每列取個名字
out:    a   b   c   d message
     0  1   2   3   4   hello
     1  5   6   7   8   world
     2  9  10  11  12     foo
 
 in: pd.read_csv('examples\ex2.csv', names=['a','b','c','d','message'],index_col='message')  # 還可以把 message 這列作為 DataFrame 的行索引
out:          a   b   c   d
     message               
     hello    1   2   3   4
     world    5   6   7   8
     foo      9  10  11  12

4.1.2 txt 數據:處理分隔符

csv 數據相對來説更規則,那麼如何讀取 txt 數據呢?

我們來看個 txt 數據的例子:

 in: with open('examples\ex3.txt','r') as f:  # 這樣可以用普通的 python 方法打開一個 txt 文件
         print(f.read())  
out:             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  # 看上去十分整潔
        
 in: list(open('examples\ex3.txt'))  # 換種方式看看
out: ['            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']
# 可以看到這個 txt 文件中,充斥着分隔符,分隔符包括:單個空格、多個空格和換行符

現在讓我們來將這個 txt 數據導入為 DataFrame:

 in: df = pd.read_table('examples\ex3.txt')
     df
out:                A         B         C
     0  aaa -0.264438 -1.026059 -0.619500
     1  bbb  0.927272  0.302904 -0.032399
     2  ccc -0.264273 -0.386314 -0.217601
     3  ddd -0.871858 -0.348382  1.100491  # 這個結果看上去很好
        
 in: df.columns  # 但如果我們看看它的列標籤,我們就會知道這不是我們想要的結果
out: Index(['            A         B         C'], dtype='object')

出現上述問題的原因是,不同的分隔符讓 pandas 難以識別行與列的分隔。如何解決這個問題呢?我們可以像前面提到的,指定 sep 參數,讓 pandas 識別出分隔符。但是分隔符包括單個空格、多個空格和換行符,如何表示這三種分隔符呢?我們用到了正則表達式:

# 此處用到了正則表達式:\s 代表空格和換行符,+ 代表可以包括1個至多個加號前面的字符——即多個空格
 in: df = pd.read_table('examples\ex3.txt',sep='\s+')
     df.columns
out: Index(['A', 'B', 'C'], dtype='object')  # 這回是我們想要的結果了

4.1.3 跳過表格前幾行

有的人在編寫表格時,喜歡在表格的前幾行備註一些信息。我們需要跳過無意義的備註信息。

比如這個文件 “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

我們想要跳過無意義的第1、3、4行,只需要指定 skiprows 參數就可以了:

 in: pd.read_csv('examples\ex4.csv',skiprows=[0,2,3])
out:    a   b   c   d message
     0  1   2   3   4   hello
     1  5   6   7   8   world
     2  9  10  11  12     foo

4.1.4 excel 數據

如今,我們處理表格數據最常用的軟件就是 Excel,保存下來的表格文件,通常是 xlsx 文件。我最常用的打開此類數據的方式是:

path = r'一個數據.xlsx'
df = pd.read_excel(path, engine='openpyxl', dtype=object, keep_default_na=False)

讓我來解釋一下 pd.read_excel() 中我使用的參數:

  • 之前曾經出現過 Excel xlsx file; not supported - 簡書 (jianshu.com) 這篇文章描述過的錯誤,因此我導入 xlsx 文件是通常會把 engine 參數設置為 'openpyxl'。但現在似乎不再需要了。
  • dtype 設置為 object,可以保留數據的原貌
  • keep_default_na = False 可以不將缺失值設置為 NaN

4.1.5 缺失值處理

讓我們來看一個有缺失值的數據:

 in: pd.read_csv('examples\ex5.csv')
out:   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,那麼可以像上面一樣,設置 keep_default_na = False。

如果除了空值,其他的某個值(比如 foo)也代表缺失值,我們想讓等於 foo 的值也表現為 NaN:

 in: pd.read_csv('examples\ex5.csv',na_values=['foo'])
out:   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     NaN

4.1.6 JSON 數據

我們在處理從網上爬到的數據時,往往需要處理 JSON 數據。如:

 in: obj = """
     {"name": "Wes",
      "places_lived": ["United States", "Spain", "Germany"],
      "pet": null,
      "siblings": [{"name": "Scott", "age": 30, "pets": ["Zeus", "Zuko"]},
                   {"name": "Katie", "age": 38,
                    "pets": ["Sixes", "Stache", "Cisco"]}]
     }
     """  # 我們定義一個 JSON 數據
     obj  # 我們得到了一個 JSON 格式的字符串
out: '\n{"name": "Wes",\n "places_lived": ["United States", "Spain", "Germany"],\n "pet": null,\n "siblings": [{"name": "Scott", "age": 30, "pets": ["Zeus", "Zuko"]},\n              {"name": "Katie", "age": 38,\n               "pets": ["Sixes", "Stache", "Cisco"]}]\n}\n'

為了能夠處理這個 JSON 字符串,我們需要將它轉換為 Python 的字典形式:

 in: import json
     result = json.loads(obj)  # 我們通過 json.loads() 進行轉換
     result  # 可以看到,現在它變成了一個字典
out: {'name': 'Wes', 'places_lived': ['United States', 'Spain', 'Germany'], 'pet': None, 'siblings': [{'name': 'Scott', 'age': 30, 'pets': ['Zeus', 'Zuko']}, {'name': 'Katie', 'age': 38, 'pets': ['Sixes', 'Stache', 'Cisco']}]}

現在,這個數據就可以轉化為 DataFrame 處理了:

 in: pd.DataFrame(result['siblings'])  # 傳入字典列表
out:     name  age                    pets
     0  Scott   30            [Zeus, Zuko]
     1  Katie   38  [Sixes, Stache, Cisco]
        
 in: pd.DataFrame(result['siblings'],columns=['name','age'])
out:     name  age
     0  Scott   30
     1  Katie   38

Python 字典同樣可以轉換回 JSON 字符串:

 in: json.dumps(result)  # 我們通過 json.dumps() 進行轉換
out: '{"name": "Wes", "places_lived": ["United States", "Spain", "Germany"], "pet": null, "siblings": [{"name": "Scott", "age": 30, "pets": ["Zeus", "Zuko"]}, {"name": "Katie", "age": 38, "pets": ["Sixes", "Stache", "Cisco"]}]}'

當然,pandas 也可以直接讀取 JSON 文件,但是 JSON 文件的格式最好規整。

 in: pd.read_json('examples/example.json')
out:    a  b  c
     0  1  2  3
     1  4  5  6
     2  7  8  9

4.2 逐塊讀取文本數據

在處理大文件時,我們常常希望讀取其中的一小塊。

比如這個有 10000 行數據的文件:

# 為了顯示好看,我們先讓 pandas 在展示時只顯示 10 行
pd.options.display.max_rows = 10  # 讓 pandas 在展示的時候只顯示10行

 in: df = pd.read_csv('examples/ex6.csv')
     df
out:            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]

為了逐塊讀取文件,我們需要指定塊的大小。比如,我們按一塊 1000 行來讀取。

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)

4.3 導出數據

表格數據我們通常會導出為 csv 或 xlsx 文件。這樣就可以導出了:

data = pd.read_csv('examples/ex5.csv')  # 首先我們讀一個文件

path = r"一個文件.csv"
data.to_csv(path)  # 這樣就導出了

path = r"一個文件.xlsx"
data.to_excel(path, index=False)  # 將 index 設置為 False 可以不輸出索引
注:轉載請註明出處。

本文屬於《利用 Python 進行數據分析》讀書筆記系列:

利用 Python 進行數據分析 —— 1 數據結構、函數和文件
利用 Python 進行數據分析 —— 2 NumPy 基礎
利用 Python 進行數據分析 —— 3 pandas 入門

user avatar wangyaxi 頭像 timliu_621f402489e7c 頭像
2 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.