Pandas 魔法筆記(1)-常用招式總覽

不管你是爬蟲、主觀選股、機器學習AI選股,你都少不了使用Pandas做資料處理,沒有處理好的資料丟入再好的模型,出來的結果也是差強人意。

Finlab課堂上同學們的問題有60%以上都是在資料整合的問題中卡住,若學好Pandas的基本功,許多事情將迎刃而解,Excel有的功能,你通通可以用Python輕鬆解決,且效能更好,還可以客製化許多功能。

Pandas功能繁多,究竟哪些是最實用的函數呢?會應用在財經數據處理的哪些場景?這篇文章將整理出最實用的招式,當您開發選股程式卡關時,可來查詢這篇筆記複習可用的工具。

pandas資料結構

Pandas的底層數值型態為Numpy,採用Array(陣列)的形式來操作資料矩陣,同學們常分不清list和array的差異,外表也確實很像,最主要的差別在list中的資料型別不必相同,而array的中的型別必須全部相同,像是list_data=[1,2,3,’Hi’]裡有不同型別的資料,增加了儲存和消耗cpu,效能會比統一型別的array差,在運算大型數據時,差距感受會很明顯。

series

Pandas最基本的操作物件,資料型態為一維陣列,由values和index組成,index預設值是RangeIndex(start=0, stop=資料長度, step=1)來說。你可以視一個series為一欄資料序列,而多個series可形成一個table矩陣,有多欄資料,組成另一個重要操作物件:Dataframe。

# 常用方法
import pandas as pd
# 產生series
series=pd.Series(data=[1,2,3,4,5,6],index=range(1,7))
# 取出內容值陣列
series.values
# 取出索引陣列
series.index
# 檢查內容值是否不重複
series.is_unique
# series繪圖
import matplotlib.pyplot as plt
series.plot()

dataframe(簡稱df)

與Series差異在data的部分是多維資料,data參數可以填入dict形式或是陣列形式,通常都使用dict。df非常相容於dict的特性,像取df特定欄位的語法為df[‘欄位名’],dict的key剛好等於df的columns,dict的value剛好等於df的values。df物件的方法包括series的操作方法。index可以用tuple list來設定多重索引。

# 常用方法
import pandas as pd
# 產生單一索引DataFrame,以下4個方法都可以
df = pd.DataFrame(data ={'A':[7,8,9],'B':[1,2,3],'C':[4,5,6]})
df = pd.DataFrame(data = np.array([(7,8,9),(1,2,3),(4,5,6)]),columns=['A','B','C'] )
df = pd.DataFrame(data = [(7,8,9),(1,2,3),(4,5,6)],columns=['A','B','C'] )
df = pd.DataFrame(data = [[7,8,9],[1,2,3],[4,5,6]],columns=['A', 'B','C'] )

# 新增欄位
df['D']=[1,2,3]

#重新命名欄位
df.columns=['1','2','3','4']

# 雙索引範例
tuples = [
   ('cobra', 'mark i'), ('cobra', 'mark ii'),
   ('sidewinder', 'mark i'), ('sidewinder', 'mark ii'),
   ('viper', 'mark ii'), ('viper', 'mark iii')
]
index = pd.MultiIndex.from_tuples(tuples)
values = [[12, 2], [0, 4], [10, 20],
        [1, 4], [7, 1], [16, 36]]
df = pd.DataFrame(values, columns=['max_speed', 'shield'], index=index)

# 取出欄位名稱
df.columns
# 取出內容值陣列
df.values
# 取出索引陣列
df.index
# 資料維度
df.shape
# 資料轉置,索引與欄位翻轉
df.T

資料篩選

loc與iloc為最常用的資料切片方法,前者以值來選取,後者以定位的數值來選取。兩者皆用list[]來操縱索引和欄位的切片。另外也有at和iat可使用,差別在at和iat是直接取value出來,而不是取series或dataframe格式。

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.loc.html

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.at.html

df = pd.DataFrame(data ={'A':[7,8,9],'B':[1,2,3],'C':[4,5,6]},index=['date1','date2','date3'])

# 取出單一欄位,型態為Series
df.A
df['A']
df.iloc[:,0]
# 取出單一欄位,型態為Dataframe
df.loc[:,['A']]
df.iloc[:,0:1]
# 取出多欄位,型態為Dataframe
df[['A','B']]
df.loc[:,['A','B']]
df.iloc[:,:2]

# 使用loc與Boolean list篩選
df.loc[df['A'] > 7]
df.loc[[False, True, True]]
df.loc[lambda df: df['A'] >7]

# 雙索引範例
tuples = [
   ('cobra', 'mark i'), ('cobra', 'mark ii'),
   ('sidewinder', 'mark i'), ('sidewinder', 'mark ii'),
   ('viper', 'mark ii'), ('viper', 'mark iii')
]
index = pd.MultiIndex.from_tuples(tuples)
values = [[12, 2], [0, 4], [10, 20],
        [1, 4], [7, 1], [16, 36]]
df_multi = pd.DataFrame(values, columns=['max_speed', 'shield'], index=index)

# 雙索引資料使用loc切片時需將索引值以tuple來取值
df_multi.loc[('cobra', 'mark i')]
df_multi .loc[('cobra', 'mark i'):('viper', 'mark ii')]

資料數值處理

apply

應用於將函數鑲嵌到df的欄位做處理,通常會結合匿名函數lambda來處理欄位裡的數值,像是我們想把某欄的“,”去掉、取代字元處理(結合str.replace),或是自己寫函數依據欄位值當變數產生客製化資料就可以使用apply。

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.apply.html

astypes

欄位資料型態轉換,處理爬蟲時很常會碰到文字、數字、日期格式互轉的問題。

to_datetime、to_timedelta、to_numeric也是pandas常見的數值轉換工具。

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.astype.html

drop

刪去不需要的欄列,像有時太多多餘資料,且需要的欄位又十分散亂,切片又不好使用時,可使用drop刪除不需要的資料。

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.drop.html

drop_duplicates

移除重複。subset為重複欄位基準設定,keep參數可選擇要保留重複列的第一筆還是最後一筆。

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.drop_duplicates.html

dropna

依據na值來決定刪去不需要的欄列,像有時拉出財報,發現某些財報項目在一些股票並沒有出現,此時會產生na,為了過濾資料,dropna就可派上用場。要注意的是axis參數決定要以欄或列為單位來處理,how參數中的all和any決定該列和該行是要全部為na,還是有一個值為na就要刪除,thresh參數決定要保留有幾個非na值的行列。

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.dropna.html

fillna

缺失值處理非常常使用,像是股價遇到暫停交易時,可能會有空值,這時我們需要用fillna來拿暫停交易前一天的股價來補,不然在回測運算時會產生錯誤。特別要注意的是method參數中的ffill和bifill,前者是拿na前的資料補,後者是拿na後的資料補。limit參數決定要補幾個na,預設是全補。

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.fillna.html

head, tail

取前、後幾筆資料,預設值為5。

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.head.html

isna, isnull, notna, notnull

檢查是否有na值或空值。

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.isna.html

rolling

滾動式計算,非常常用在計算指標,如產生近3月平均營收的時間序列。參數min_periods有時會用到,決定要至少多少數值才列入計算,如想要近11月平均營收,但資料卻只有近5月,就會被放掉,若沒有特別設定,就是用近X月來算。

set_index, reset_index

將特定欄位轉乘索引、重置索引(索引轉正常欄位)。

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.set_index.html

shift

平移時間序列數值,此用場景在回測應用,像是營收資料在10號公佈,但我們買進的股價會在11號,這時算回社時,就不能用10號買入價計算,必須要用shift來平移數據。

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.shift.html

sort_values , sort_index

兩個差異在要使用數值還是索引值資料排序。ascending參數決定升降冪,key參數可結合lambda做更複雜的排序方法。

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.sort_values.html

sum, max, min, mean, std, cumsum, cumprod

分別為加總、最大值、最小值、平均值、標準差、累加、累成。常用於策略撰寫、指標開發、回測報酬率計算。經常搭配rolling方法使用。

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.sum.html#pandas.Series.sum

to_frame, to_series, tolist

dataframe、series、list資料格式互相轉換,當一維數據的series需要用dataframe才有的方法處理時,要先用to_frame來轉換。

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.to_frame.html

資料合併

merge, join, concatenate

處理資料合併,像是要把上市、上櫃、興櫃個市場價格資料合併成一張dataframe做計算。如果熟悉excel,就不會陌生。基本上3個都能達成功能。

https://pandas.pydata.org/pandas-docs/stable/user_guide/merging.html

reindex

索引對照,將A的index套入B的index,例如想以月營收每月10號的時間套入股價資料,讓股價資料只顯示月營收公布日對應的數據。

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.reindex.html

資料分群

cut

Cut方法可以處理分類datafrme的資料,像我們常想把財報中ROE>20的標的分類為A、20>ROE>10為B、ROE>10為C,這時我們就可使用cut來輕鬆達成。之後使用groupby分群集合運算或是切片選取都非常方便。

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.cut.html

groupby

group運算式不論在DB或Excel都有設置,是常使用的工具。可以幫我們分群整合運算,像我們要計算個股分點券商買賣超,就需要以stock_id當分群依據,之後用sum來加總每支個股的主力買賣超,也可以應用在計算各類股平均漲跌幅,以產業類別當分群依據。

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.groupby.html

pivot

pivot方法可以重塑資料的shape,像課堂中大家常用的data.get()背後就是將雙索引資料解構成“columns=stock_id、index=date”的格式。stack與unstack也提供類似的功能,並可以互轉調整。

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.pivot.html

時間序列

date_range

產生時間序列,應用場景於重塑特定時間序列來回測,例如想將date序列換成每月10號,可使用date_range快速產生日期區間,用簡易的start與end參數來控制。

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.date_range.html

顯示設定

options and settings

很多人會覺得jupyter不方便如excel般審視資料,因為大量數據只會顯示前後10筆,中間會用’…’略過,能否解決這問題呢?set_option讓我們可以改變一些pandas的預設設定,想全展資料,用下列程式碼就可解決。

https://pandas.pydata.org/pandas-docs/stable/user_guide/options.html

pd.set_option("display.max_rows", None)

資料輸出/讀取

pandas提供多種格式可以輸出/輸入資料。

https://pandas.pydata.org/pandas-docs/stable/reference/io.html

df = pd.DataFrame(data ={'A':[7,8,9],'B':[1,2,3],'C':[4,5,6]})

# 輸出方法
df.to_csv('檔名.csv')
df.to_excel('檔名.xls')
df.to_pickle('檔名.pkl')

# 詳見 https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_sql.html
df.to_sql('table_name', con=' DB engine')

#讀取方法將to改成read,ex:df.read_csv('檔名.csv')

Genie

Python elf, love magic of python. Explore the financial world.