Pandas 輸入輸出


在資料的輸入方面,Pandas 提供了豐富的 API,可以讀取各種格式的檔案,像是常見的 CSV、Excel、JSON 等,以讀取 CSV 為例,若 score.csv 有以下內容:

數學,英文,物理
90,99,100
99,87,94
92,85,76
87,67,72
85,89,67

讀入的資料自動封裝為 DataFrame 傳回,因此底下的程式就可以讀取並顯示圖表:

import matplotlib.pyplot as plt
import pandas as pd

pd.read_csv('score.csv').plot()
plt.show()

顯示的結果如下:

Pandas 輸入輸出

圖表中的 x 軸預設使用數字索引是個問題,另一方面,來源資料實際上往往需要進一步的處理,以〈NumPy 載入文字檔〉中發行量加權股價指數歷史資料的 CSV 檔案為例,若使用以下的程式讀入:

import pandas as pd

hist = pd.read_csv('MI_5MINS_HIST.csv', encoding = 'Big5')
print(hist)

會顯示以下的內容:

                                                   110年01月 發行量加權股價指數歷史資料
日期        開盤指數      最高指數      最低指數      收盤指數                         NaN
110/01/04 14,720.25 14,937.13 14,720.25 14,902.03                    NaN
110/01/05 14,913.64 15,000.03 14,861.99 15,000.03                    NaN
110/01/06 15,145.85 15,197.68 14,837.00 14,983.13                    NaN
110/01/07 15,059.52 15,270.40 15,049.86 15,214.00                    NaN
...

第一列的資料是不需要的,而且最後一行是 NaN?這是因為來源 CSV 檔案每一列最後都有個逗號,等於多一個欄位,而該欄位沒有資料,這時 Pandas 會自行補上 NaN。

第一列的資料可以指定 skiprows 來略過,至於不需要的最後一行,可以透過 iloc 來去除:

hist = pd.read_csv('MI_5MINS_HIST.csv', 
            encoding = 'Big5', 
            skiprows = 1, 
            index_col = '日期').iloc[:,:-1]

上例中也透過 index_col 指定了日期作為索引行,行的選擇也可以透過 usecols,例如:

hist = pd.read_csv('MI_5MINS_HIST.csv', 
            encoding = 'Big5', 
            skiprows = 1, 
            usecols = ['日期', '開盤指數', '最高指數', '最低指數', '收盤指數'], 
            index_col = '日期')

讀入的資料是以日期作為索引,然而指數部份需要數值才能繪圖,因而需要進一步處理,若是 DataFrame,可以透過 applymap,指定對行元素全部套用的函式,例如:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import locale

locale.setlocale(locale.LC_NUMERIC, 'zh_TW.UTF-8')
atof = np.frompyfunc(locale.atof, 1, 1)

hist = pd.read_csv('MI_5MINS_HIST.csv', 
            encoding = 'Big5', 
            skiprows = 1, 
            index_col = '日期').iloc[:,:-1]

# 對元素套用函式
ax = hist.applymap(atof).plot()
ax.yaxis.set_major_formatter(ticker.StrMethodFormatter('{x:,.0f}'))

plt.gcf().autofmt_xdate()
plt.show()

對於 Series 的話,可以使用 map,另外還有個 apply,可以針對 SeriesDataFrame,指定 axis 來套用函式。

以上範例可以顯示的圖形如下:

Pandas 輸入輸出

看到上圖,你可能會想說,能不能畫個 K 線圖(candlestick chart)吧!這需要 mplfinance,必須額外安裝,例如:

pip install --upgrade mplfinance

mplfinance 的前身是已經被廢棄的 mpl-finance,透過以上指令,如果已經存在 mpl-finance,就會昇級為 mplfinance,直接來看怎麼畫 K 線圖:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import locale
import mplfinance as mpf
from datetime import datetime

def date_parser(minguo):
    y, m, d = minguo.split('/')
    year = int(y) + 1911 # 轉西元年
    return datetime.strptime(f'{year}/{m}/{d}', '%Y/%m/%d')

locale.setlocale(locale.LC_NUMERIC, 'zh_TW.UTF-8')
atof = np.frompyfunc(locale.atof, 1, 1)

hist = pd.read_csv('MI_5MINS_HIST.csv', 
            encoding = 'Big5', 
            skiprows = 1, 
            index_col = 0, 
            date_parser = date_parser).iloc[:,:-1].applymap(atof)

hist.to_csv('xxx.csv') # 另存 CSV 

mpf.plot(hist, type='candle', style='charles', 
         columns = ['開盤指數', '最高指數', '最低指數', '收盤指數', '成交量'])

plt.show()

mplfinance 會使用日期索引,而且必須是 DatetimeIndex 實例,這可以透過 read_csvindex_col 指定欄位,然而〈NumPy 載入文字檔〉中發行量加權股價指數歷史資料的 CSV 檔案中,日期使用的是民國年,在剖析日期時必須使用西元年,因此這邊自行指定了 date_parser

mplfinance 預設必須使用的欄位順序是 'open''high''low''close' 以及一個選擇性的 'volume',你可以直接更改 DataFramecolumns,或者是呼叫 mplfinanceplot 時透過 columns 指定自訂的欄位名稱,雖然 'volume' 是選擇性的,不過透過 columns 自訂欄位名稱時,必須都列出來。

如果你想要將處理過後的資料存下來,DataFrame 提供了 to_csvto_excelto_json 等方法。

以上的範例畫出來的圖如下:

Pandas 輸入輸出