一、pandas簡介

pandas含有使數據清洗和分析工作變得更快更簡單的數據結構和操作工具。pandas經常和其它工具一同使用,如數值計算工具NumPy和SciPy,分析庫statsmodels和scikit-learn,和數據可視化庫matplotlib。pandas是基於NumPy數組構建的,特別是基於數組的函數和不使用for循環的數據處理。

pandas是專門為處理表格和混雜數據設計的。而NumPy更適合處理統一的數值數組數據。pandas引入約定:

In [1]: import pandas as pd

因此,只要你在代碼中看到pd.,就得想到這是pandas。因為Series和DataFrame用的次數非常多,所以將其引入本地命名空間中會更方便:

In [2]: from pandas import Series, DataFrame

二、實例

2.12排序和排名

根據條件對數據集排序也是一種重要的內置運算。要對行或列索引按字典順序進行排序,可使用sort_index方法,它將返回一個已排序的新對象:

In [201]: obj = pd.Series(range(4), index=[d, a, b, c])

In [202]: obj.sort_index()

Out[202]:

a 1

b 2

c 3

d 0

dtype: int64

對於DataFrame,則可以根據任意一個軸上的索引進行排序:

In [203]: frame = pd.DataFrame(np.arange(8).reshape((2, 4)),

.....: index=[three, one],

.....: columns=[d, a, b, c])

In [204]: frame.sort_index()

Out[204]:

d a b c

one 4 5 6 7

three 0 1 2 3

In [205]: frame.sort_index(axis=1)

Out[205]:

a b c d

three 1 2 3 0

one 5 6 7 4

數據默認是按升序排序的,但也可以降序排序:

In [206]: frame.sort_index(axis=1, ascending=False)

Out[206]:

d c b a

three 0 3 2 1

one 4 7 6 5

若要按值對Series進行排序,可使用其sort_values方法:

In [207]: obj = pd.Series([4, 7, -3, 2])

In [208]: obj.sort_values() #按數值排列

Out[208]:

2 -3

3 2

0 4

1 7

dtype: int64

在排序時,任何缺失值默認都會被放到Series的末尾:

In [209]: obj = pd.Series([4, np.nan, 7, np.nan, -3, 2])

In [210]: obj.sort_values()

Out[210]:

4 -3.0

5 2.0

0 4.0

2 7.0

1 NaN

3 NaN

dtype: float64

當排序一個DataFrame時,你可能希望根據一個或多個列中的值進行排序。將一個或多個列的名字傳遞給sort_values的by選項即可達到該目的:

In [211]: frame = pd.DataFrame({b: [4, 7, -3, 2], a: [0, 1, 0, 1]})

In [212]: frame #行號自動生成

Out[212]:

a b

0 0 4

1 1 7

2 0 -3

3 1 2

In [213]: frame.sort_values(by=b) #依據b列從小到大排序

Out[213]:

a b

2 0 -3

3 1 2

0 0 4

1 1 7

要根據多個列進行排序,傳入名稱的列表即可:

In [214]: frame.sort_values(by=[a, b])#優先按a列,如a相同則按b

Out[214]:

a b

2 0 -3

0 0 4

3 1 2

1 1 7

接下來介紹Series和DataFrame的rank方法。默認情況下,rank通過「為各組分配一個平均排名」的方式體現排名:

In [215]: obj = pd.Series([7, -5, 7, 4, 2, 0, 4])

In [216]: obj.rank()

Out[216]:

0 6.5

1 1.0

2 6.5

3 4.5

4 3.0

5 2.0

6 4.5

dtype: float64

註:7在整個Series中出現兩次,按從小到大排列分別排在第六和第七,所以取兩個排名的均值,即6.5,其餘類似.

也可以根據值在原數據中出現的順序給出排名:

In [217]: obj.rank(method=first)

Out[217]:

0 6.0

1 1.0

2 7.0

3 4.0

4 3.0

5 2.0

6 5.0

dtype: float64

這裡,條目0和2沒有使用平均排名6.5,它們被設成了6和7,因為數據中標籤0位於標籤2的前面。

你也可以按降序進行排名:

In [218]: obj.rank(ascending=False, method=max)

Out[218]:

0 2.0

1 7.0

2 2.0

3 4.0

4 5.0

5 6.0

6 4.0

dtype: float64

此處的max表示當出現兩個一樣的排名,如7出現兩次,按從小到大排列分別排在第六和第七,則取排名較大的,取7,ascending默認為True,從小到大,改為false則倒序排列。

DataFrame可以在行或列上計算排名:

In [219]: frame = pd.DataFrame({b: [4.3, 7, -3, 2], a: [0, 1, 0, 1], c: [-2, 5, 8, -2.5]})

In [220]: frame

Out[220]:

b a c

0 4.3 0 -2.0

1 7.0 1 5.0

2 -3.0 0 8.0

3 2.0 1 -2.5

In [221]: frame.rank(axis=columns) #每個元素在同行不同列中的排名

Out[221]:

b a c

0 3.0 2.0 1.0

1 3.0 1.0 2.0

2 1.0 2.0 3.0

3 3.0 2.0 1.0

2.13 帶有重複標籤的軸索引

直到目前為止,我所介紹的所有範例都有著唯一的軸標籤(索引值)。雖然許多pandas函數都要求標籤唯一,但這並不是強制性的。我們來看看下面這個簡單的帶有重複索引值的Series:

In [222]: obj = pd.Series(range(5), index=[a, a, b, b, c])

In [223]: obj

Out[223]:

a 0

a 1

b 2

b 3

c 4

dtype: int64

索引的is_unique屬性可以告訴你它的值是否唯一:

In [224]: obj.index.is_unique

Out[224]: False

對於帶有重複值的索引,數據選取的行為將會有些不同。如果某個索引對應多個值,則返回一個Series;而對應單個值的,則返回一個標量值:

In [225]: obj[a]#索引重複,則返回Series

Out[225]:

a 0

a 1

dtype: int64

In [226]: obj[c]

Out[226]: 4

這樣會使代碼變複雜,因為索引的輸出類型會根據標籤是否有重複發生變化。

對DataFrame的行進行索引時也是如此:

In [227]: df = pd.DataFrame(np.random.randn(4, 3), index=[a, a, b, b])

In [228]: df

Out[228]:

0 1 2

a 0.274992 0.228913 1.352917

a 0.886429 -2.001637 -0.371843

b 1.669025 -0.438570 -0.539741

b 0.476985 3.248944 -1.021228

In [229]: df.loc[b]#返回所有索引為b的字元

Out[229]:

0 1 2

b 1.669025 -0.438570 -0.539741

b 0.476985 3.248944 -1.021228

2.14 匯總和計算描述統計

pandas對象擁有一組常用的數學和統計方法。它們大部分都屬於約簡和匯總統計,用於從Series中提取單個值或從DataFrame的行或列中提取一個Series。跟對應的NumPy數組方法相比,它們都是基於沒有缺失數據的假設而構建的。看一個簡單的DataFrame:

In [230]: df = pd.DataFrame([[1.4, np.nan], [7.1, -4.5],

.....: [np.nan, np.nan], [0.75, -1.3]],

.....: index=[a, b, c, d],

.....: columns=[one, two])

In [231]: df

Out[231]:

one two

a 1.40 NaN

b 7.10 -4.5

c NaN NaN

d 0.75 -1.3

調用DataFrame的sum方法將會返回一個含有列的和的Series:

In [232]: df.sum() #按列求和,nan計為0

Out[232]:

one 9.25

two -5.80

dtype: float64

傳入axis=columns或axis=1將會按行進行求和運算:

In [233]: df.sum(axis=1)#按行求各列的和,nan計為0

Out[233]:

a 1.40

b 2.60

c NaN

d -0.55

NA值會自動被排除,除非整個切片都是NA。通過skipna選項可以禁用該功能:

In [234]: df.mean(axis=columns, skipna=False)

Out[234]:

a NaN

b 1.300

c NaN

d -0.275

dtype: float64

有些方法返回的是間接統計(比如達到最小值或最大值的索引):

In [235]: df.idxmax() #每列最大值的行號

Out[235]:

one b

two d

dtype: object

另一些方法則是累計型的:

In [236]: df.cumsum() #每列逐行累加求和

Out[236]:

one two

a 1.40 NaN

b 8.50 -4.5

c NaN NaN

d 9.25 -5.8

還有一種方法,它既不是約簡型也不是累計型。describe就是一個例子,它用於一次性產生多個匯總統計:

In [237]: df.describe()

Out[237]:

one two

count 3.000000 2.000000 #可用元素

mean 3.083333 -2.900000 #平均數

std 3.493685 2.262742 #標準差

min 0.750000 -4.500000 #最小值

25% 1.075000 -3.700000 #分位數

50% 1.400000 -2.900000 #分位數

75% 4.250000 -2.100000 #分位數

max 7.100000 -1.300000 #最大值

對於非數值型數據,describe會產生另外一種匯總統計:

In [238]: obj = pd.Series([a, a, b, c] * 4)

In [239]: obj.describe()#obj相當於把列表重複了4次的一個Series

Out[239]:

count 16

unique 3 #不重複個數

top a #出現最多的元素

freq 8 #top元素出現次數

dtype: object

2.15相關係數與協方差

有些匯總統計是通過參數對計算出來的。我們來看幾個DataFrame,它們的數據來自股票價格和成交量,使用的是pandas-datareader包,該包可以便捷地獲取一些數據:

conda install pandas-datareader

我使用pandas_datareader模塊下載了一些股票數據:

import pandas_datareader.data as web

all_data = {ticker: web.get_data_yahoo(ticker)

for ticker in [AAPL, IBM, MSFT, GOOG]}

price = pd.DataFrame({ticker: data[Adj Close]

for ticker, data in all_data.items()})

volume = pd.DataFrame({ticker: data[Volume]

for ticker, data in all_data.items()})

In [242]: returns = price.pct_change()

In [243]: returns.tail()

Out[243]:

AAPL IBM MSFT GOOG

Date

2019-04-29 0.001517 -0.002797 -0.000924 0.012105

2019-04-30 -0.019256 0.008774 0.006396 -0.076966

2019-05-01 0.049086 0.002067 -0.020827 -0.017165

2019-05-02 -0.006508 -0.006901 -0.013059 -0.004683

2019-05-03 0.012431 0.004728 0.021314 0.019602

Series的corr方法用於計算兩個Series中重疊的、非NA的、按索引對齊的值的相關係數。與此類似,cov用於計算協方差:

In [244]: returns[MSFT].corr(returns[IBM])#相關係數

Out[244]: 0.4852886668057154

In [245]: returns[MSFT].cov(returns[IBM])#協方差

Out[245]: 8.643793758110261e-05

因為MSTF是一個合理的Python屬性,我們還可以用更簡潔的語法選擇列:

In [246]: returns.MSFT.corr(returns.IBM)

Out[246]: 0.4852886668057154

另一方面,DataFrame的corr和cov方法將以DataFrame的形式分別返回完整的相關係數或協方差矩陣:

In [247]: returns.corr()

Out[247]:

AAPL IBM MSFT GOOG

AAPL 1.000000 0.369996 0.448064 0.455816

IBM 0.369996 1.000000 0.485289 0.403171

MSFT 0.448064 0.485289 1.000000 0.534275

GOOG 0.455816 0.403171 0.534275 1.000000

In [248]: returns.cov()

Out[248]:

AAPL IBM MSFT GOOG

AAPL 0.000269 0.000075 0.000106 0.000115

IBM 0.000075 0.000152 0.000086 0.000077

MSFT 0.000106 0.000086 0.000209 0.000119

GOOG 0.000115 0.000077 0.000119 0.000238

利用DataFrame的corrwith方法,你可以計算其列或行跟另一個Series或DataFrame之間的相關係數。傳入一個Series將會返回一個相關係數值Series(針對各列進行計算):

In [249]: returns.corrwith(returns.IBM)

Out[249]:

AAPL 0.386817

GOOG 0.405099

IBM 1.000000

MSFT 0.499764

dtype: float64

傳入一個DataFrame則會計算按列名配對的相關係數。這裡,我計算百分比變化與成交量的相關係數:

In [250]: returns.corrwith(volume)

Out[250]:

AAPL -0.075565

GOOG -0.007067

IBM -0.204849

MSFT -0.092950

dtype: float64

傳入axis=columns即可按行進行計算。無論如何,在計算相關係數之前,所有的數據項都會按標籤對齊。

2.16唯一值、值計數以及成員資格

還有一類方法可以從一維Series的值中抽取信息。看下面的例子:

In [251]: obj = pd.Series([c, a, d, a, a, b, b, c, c])

第一個函數是unique,它可以得到Series中的唯一值數組:

In [252]: uniques = obj.unique()

In [253]: uniques

Out[253]: array([c, a, d, b], dtype=object)

返回的唯一值是未排序的,如果需要的話,可以用uniques.sort()對結果再次進行排序。類似的情況,value_counts用於計算一個Series中各值出現的頻率:

In [254]: obj.value_counts()

Out[254]:

c 3

a 3

b 2

d 1

dtype: int64

為了便於查看,結果Series是按值頻率降序排列的。value_counts還是一個頂級pandas方法,可用於任何數組或序列:

In [255]: pd.value_counts(obj.values, sort=False)

Out[255]:

a 3

b 2

c 3

d 1

dtype: int64

isin用於判斷矢量化集合的成員資格,可用於過濾Series中或DataFrame列中數據的子集:

In [256]: obj

Out[256]:

0 c

1 a

2 d

3 a

4 a

5 b

6 b

7 c

8 c

dtype: object

In [257]: mask = obj.isin([b, c])

In [258]: mask

Out[258]:

0 True

1 False

2 False

3 False

4 False

5 True

6 True

7 True

8 True

dtype: bool

In [259]: obj[mask]#只取滿足條件的

Out[259]:

0 c

5 b

6 b

7 c

8 c

dtype: object

與isin類似的是Index.get_indexer方法,它可以給你一個索引數組,從可能包含重複值的數組到另一個不同值的數組:

In [260]: to_match = pd.Series([c, a, b, b, c, a])

In [261]: unique_vals = pd.Series([c, b, a])

In [262]: pd.Index(unique_vals).get_indexer(to_match)

#to_match中各元素在索引數組中的位置

Out[262]: array([0, 2, 1, 1, 0, 2])

有時,你可能希望得到DataFrame中多個相關列的一張柱狀圖。例如:

In [263]: data = pd.DataFrame({Qu1: [1, 3, 4, 3, 4],

.....: Qu2: [2, 3, 1, 2, 3],

.....: Qu3: [1, 5, 2, 4, 4]})

In [264]: data

Out[264]:

Qu1 Qu2 Qu3

0 1 2 1

1 3 3 5

2 4 1 2

3 3 2 4

4 4 3 4

將pandas.value_counts傳給該DataFrame的apply函數,就會出現:

In [265]: result = data.apply(pd.value_counts).fillna(0)

In [266]: result

Out[266]:

Qu1 Qu2 Qu3

1 1.0 1.0 1.0

2 0.0 2.0 1.0

3 2.0 2.0 0.0

4 2.0 0.0 2.0

5 0.0 0.0 1.0

這裡,結果中的行標籤是所有列的唯一值。後面的頻率值是每個列中這些值的相應計數。

三、小結

obj.sort_index()#Series索引排序

frame.sort_index()#DataFrame索引排序

frame.sort_index(axis=1)#DataFrame列排序

frame.sort_index(axis=1, ascending=False)#DataFrame列降序排序

obj.sort_values() #按數值排列

frame.sort_values(by=b) #依據b列從小到大排序

frame.sort_values(by=[a, b])#優先按a列,如a相同則按b

obj.rank() #Series的排名

obj.rank(method=first) #先出現的排名靠前

obj.rank(ascending=False, method=max) #降序,同個數值取排名大的

frame.rank(axis=columns) #每個元素在同行不同列中的排名

obj.index.is_unique#值是否唯一

obj[a]#索引重複,則返回Series

df.loc[b]#返回所有索引為b的字元

df.sum() #按列求和,nan計為0

df.sum(axis=1)#按行求各列的和,nan計為0

df.mean(axis=columns, skipna=False)#遇到NaN不跳過求平均數

df.idxmax() #每列最大值的行號

df.cumsum() #每列逐行累加求和

df.describe()

!import pandas_datareader.data as web #2.15 pandas_datareader的關聯功能相對重要,後續有可能專門寫一篇專項

uniques = obj.unique()#得到Series中的唯一值數組

obj.value_counts()#計算一個Series中各值出現的頻率

mask = obj.isin([b, c]) #是否包含列表元素

pd.Index(unique_vals).get_indexer(to_match)#to_match中各元素在索引數組中的位置

result = data.apply(pd.value_counts).fillna(0)

·後記

本章結束,我們接觸了通過pandas自帶的數據獲取工具去獲取一些數據並用DataFrame進行處理,這個是量化交易的良好開端。

目前篇幅有些過長,後續還是會合理壓縮一下,有什麼建議或 可以評論留言。

歡迎點贊·評論·分享·收藏·澆築樹苗

(o???o)? r (苗·lv.0)


推薦閱讀:
相關文章