【12月DW打卡】joyful-pandas - 02 - Pandas 基礎 (包含基本函式、視窗物件、擴張視窗等知識點)
第二章 pandas 基礎
簡單回顧和總結
- 重新回頭跟著教程走了一遍,又又又複習了一次,這次感覺效果更好了。
- 後面的第二個練習用結構化的語言寫了一遍,對上了答案,花了快兩個多小時,哎,手生了。
- 附ipynb轉md博文命令: jupyter nbconvert --to markdown E:\PycharmProjects\TianChiProject\00_山楓葉紛飛\competitions\008_joyful-pandas\02-pandas基礎.ipynb
準備:導包
import numpy as np
import pandas as pd
準備:升級pandas
pip install pandas --upgrade
pd.__version__
'1.1.5'
一、檔案的讀取和寫入
- 在使用 read_table 的時候需要注意,引數 sep 中使用的是正則表示式,因此需要對 | 進行轉義變成 | ,否則無法讀取到正確的結果。
- 一般在資料寫入中,最常用的操作是把 index 設定為 False,去除索引。
- 如果想要把表格快速轉換為 markdown 和 latex 語言,可以使用 to_markdown 和 to_latex 函式,此處需要安裝 tabulate 包。
In [20]: print(df_csv.to_markdown()) | | col1 | col2 | col3 | col4 | col5 | |---:|-------:|:-------|-------:|:-------|:---------| | 0 | 2 | a | 1.4 | apple | 2020/1/1 | | 1 | 3 | b | 3.4 | banana | 2020/1/2 | | 2 | 6 | c | 2.5 | orange | 2020/1/5 | | 3 | 5 | d | 3.2 | lemon | 2020/1/7 |
二、基本資料結構
- 一維的Series
- 二維的DataFrame
1. Series
Series 一般由四個部分組成,分別是序列的值 data 、索引 index 、儲存型別 dtype 、序列的名字 name 。其中,索引也可以指定它的名字,預設為空。
s = pd.Series(data = [100, 'a', {'dic1':5}], index = pd.Index(['id1', 20, 'third'], name='my_idx'), dtype = 'object', name = 'my_name') s
my_idx
id1 100
20 a
third {'dic1': 5}
Name: my_name, dtype: object
2. DataFrame
ataFrame 在 Series 的基礎上增加了列索引,一個數據框可以由二維的 data 與行列索引來構造:
df = pd.DataFrame(data = {'col_0': [1,2,3], 'col_1':list('abc'),
'col_2': [1.2, 2.2, 3.2]},
index = ['row_%d'%i for i in range(3)])
df
col_0 | col_1 | col_2 | |
---|---|---|---|
row_0 | 1 | a | 1.2 |
row_1 | 2 | b | 2.2 |
row_2 | 3 | c | 3.2 |
三、常用基本函式
prefix_path = 'E:\\PycharmProjects\\DatawhaleChina\\joyful-pandas\\data'
df = pd.read_csv(prefix_path+'\\learn_pandas.csv')
### 0. 查詢基本列名稱 (屬性)
df.columns
Index(['School', 'Grade', 'Name', 'Gender', 'Height', 'Weight', 'Transfer',
'Test_Number', 'Test_Date', 'Time_Record'],
dtype='object')
-
彙總函式
- df.head(2)
- df.tail(3)
- info() 返回表的資訊概況;
- describe() 返回表中數值列對應的主要統計量;
-
特徵統計函式
- 常見的如:sum, mean, median, var, std, max, min等
- 分位數:quantile,示例df.quantile(0.75)
- 非缺失值個數:count()
- 最大值對應的索引: idxmax()
- 小結:上述操作返回的都是標量,所以又稱為聚合函式,他們有一個公共引數axis,預設為0代表逐列來聚合,1代表逐行聚合!
-
唯一值函式
- unique:得到其唯一值組成的列表
- nunique:得到其唯一值組成的列表的大小
- value_counts 可以得到唯一值和其對應出現的頻數:
- drop_duplicates :刪除重複資料,其中的關鍵引數是 keep ,預設值 first 表示每個組合保留第一次出現的所在行, last 表示保留最後一次出現的所在行, False 表示把所有重複組合所在的行剔除。
- duplicated 和 drop_duplicates 的功能類似,但前者返回了是否為唯一值的布林列表,其 keep 引數與後者一致。其返回的序列,把重複元素設為 True ,否則為 False 。 drop_duplicates 等價於把 duplicated 為 True 的對應行剔除。
-
替換函式 (針對某一個列進行的)
- 對映替換:
- replace函式,可以通過字典構造,或者傳入兩個列表來進行替換
- 另外, replace 還有一種特殊的方向替換,指定 method 引數為 ffill 則為用前面一個最近的未被替換的值進行替換, bfill 則使用後面最近的未被替換的值進行替換。如: s.replace([1, 2], method='ffill')
- 正則替換,暫時不可用~
df['Gender']
0 Female
1 Male
2 Male
3 Female
4 Male
...
195 Female
196 Female
197 Female
198 Male
199 Male
Name: Gender, Length: 200, dtype: object
df['Gender'].replace({'Female': 0, 'Male': 1}).head()
0 0
1 1
2 1
3 0
4 1
Name: Gender, dtype: int64
- 邏輯替換
- 包括了 where 和 mask ,這兩個函式是完全對稱的: where 函式在傳入條件為 False 的對應行進行替換,而 mask 在傳入條件為 True 的對應行進行替換,當不指定替換值時,替換為缺失值。
s = pd.Series([-1, 1.2345, 100, -50, 999])
s.where(s<0)
0 -1.0
1 NaN
2 NaN
3 -50.0
4 NaN
dtype: float64
s.where(s<0, 100)
0 -1.0
1 100.0
2 100.0
3 -50.0
4 100.0
dtype: float64
- 需要注意的是,傳入的條件只需是與被呼叫的 Series 索引一致的布林序列即可
s_condition= pd.Series([True,False,False,True, True],index=s.index)
s.where(s<0, 6666)
0 -1.0
1 6666.0
2 6666.0
3 -50.0
4 6666.0
dtype: float64
數值替換包含了 round, abs, clip 方法,它們分別表示取整、取絕對值和截斷(比大小,超出返回的用上屆或者下屆來依次替代):
s = pd.Series([-1, 1.2345, 100, -50])
print('取整 保留兩位', s.round(2))
print('取abs', s.abs())
print('clip大法:按照大小進行範圍擷取\n', s.clip(0, 1))
# print('\n', s.clip(0, 2))
# print('\n', s.clip(0, 3))
取整 保留兩位 0 -1.00
1 1.23
2 100.00
3 -50.00
dtype: float64
取abs 0 1.0000
1 1.2345
2 100.0000
3 50.0000
dtype: float64
clip大法:按照大小進行範圍擷取
0 0.0
1 1.0
2 1.0
3 0.0
dtype: float64
-
排序函式
- 排序共有兩種方式,其一為值排序,其二為索引排序,對應的函式是 sort_values() 和 sort_index() 。
- 預設引數 ascending=True; eg: df.sort_values('Height', ascending=False).head()
- 在排序中,進場遇到多列排序的問題,比如在體重相同的情況下,對身高進行排序,並且保持身高降序排列,體重升序排列;eg: df_demo.sort_values(['Weight','Height'],ascending=[True,False]).head()
- 索引排序的用法和值排序完全一致,只不過元素的值在索引中,此時需要指定索引層的名字或者層號,用引數 level 表示。另外,需要注意的是字串的排列順序由字母順序決定。eg: df_demo.sort_index(level=['Grade','Name'],ascending=[True,False]).head()
-
apply 方法
- apply的引數往往是一個以序列為輸入的函式。
- apply效能較慢,自由度比較高。
df_demo = df[['Height', 'Weight']]
def my_mean(x):
return x.mean()
# axis=0,預設按列作為一個整體進行計算; axis=1,表示按行計算
df_demo.apply(my_mean, axis=0)
df_demo.apply(lambda x:x.mean(), axis=0)
Height 163.218033
Weight 55.015873
dtype: float64
四. 視窗物件
pandas中有三類視窗,分別是滑動視窗 rolling 、擴張視窗 expanding 以及指數加權視窗 ewm 。
4.1 滑動視窗物件 rolling
- 滑動視窗,引數為視窗大小 window,每次滾動包括當前行,前window-1行是沒有結果的。
- 使用 .rolling 得到滑窗物件roller,roller類似於一個分組,再搭配聚合函式進行輸出
- 類似的還有滑動相關係數或滑動協方差的計算,如roller.cov(s)或者roller.corr(s)
- 還支援後接上apply()方法
- 支援shift, diff, pct_change 這一組的類滑窗函式,它們的公共引數為 periods=n ,預設為 1,分別表示取向前第 n
個元素的值、與向前第 n 個元素做差(與 Numpy中的diff不同,後者表示 n 階差分)、與向前第 n 個元素相比計
算增長率。這裡的 n 可以為負,表示反方向的類似操作。
s = pd.Series([2,4,6,8,10])
s_roller_mean = s.rolling(window=3).mean()
s2 = pd.Series([1,2,6,16,30])
roller = s2.rolling(window = 3)
roller.cov(s)
roller.corr(s)
0 NaN
1 NaN
2 0.944911
3 0.970725
4 0.995402
dtype: float64
4.2 擴張視窗 expanding (從起點開始依次累加擴張指定的大小視窗——執行聚合函式)
擴張視窗又稱累計視窗,可以理解為一個動態長度的視窗,其視窗的大小就是從序列開始處到具體操作的對
應位置,其使用的聚合函式會作用於這些逐步擴張的視窗上。具體地說,設序列為 a1, a2, a3, a4,則其每個
位置對應的視窗即 [a1]、[a1, a2]、[a1, a2, a3]、[a1, a2, a3, a4]。
s = pd.Series([1, 3, 6, 10])
s.expanding().mean()
0 1.000000
1 2.000000
2 3.333333
3 5.000000
dtype: float64
4.3 練一練
cummax, cumsum, cumprod 函式是典型的類擴張視窗函式,請使用 expanding 物件依次實現它們。
#### 4.3.1 cummax
s = pd.Series([1, 3, 6, 10])
ret1 = s.cummax()
ret2 = s.expanding().max()
print('after cummax or expanding.max():')
print(ret1)
print(ret2)
#### 4.3.1 cumsum
#### 4.3.1 cumprod
# 略
after cummax or expanding.max():
0 1
1 3
2 6
3 10
dtype: int64
0 1.0
1 3.0
2 6.0
3 10.0
dtype: float64
五 練習
2.5.1 Ex1:口袋妖怪資料集
現有一份口袋妖怪的資料集,下面進行一些背景說明:
- 代表全國圖鑑編號,不同行存在相同數字則表示為該妖怪的不同狀態
- 妖怪具有單屬性和雙屬性兩種,對於單屬性的妖怪,Type 2 為缺失值
- Total, HP, Attack, Defense, Sp. Atk, Sp. Def, Speed 分別代表種族值、體力、物攻、防禦、特攻、特防、速度,其中種族值為後 6 項之和。
題目
- 對 HP, Attack, Defense, Sp. Atk, Sp. Def, Speed 進行加總,驗證是否為 Total 值。
df = pd.read_csv('E:\\PycharmProjects\\DatawhaleChina\\joyful-pandas\\data\\pokemon.csv')
df.head(3)
list_cols = ['HP', 'Attack', 'Defense', 'Sp. Atk', 'Sp. Def', 'Speed']
df['my_total'] = 0
for x in list_cols:
df['my_total'] = df['my_total'] + df[x]
if df[df['my_total']!=df['Total']].shape[0] > 0:
print('存在錯誤資料!', df[df['my_total']!=df['Total']])
else:
print('暫無錯誤資料')
del df['my_total']
暫無錯誤資料
- 對於 # 重複的妖怪只保留第一條記錄,解決以下問題:
- (a) 求第一屬性的種類數量和前三多數量對應的種類
- (b) 求第一屬性和第二屬性的組合種類
- (c) 求尚未出現過的屬性組合
print(df.columns)
df = df.drop_duplicates('#', keep='first')
Index(['#', 'Name', 'Type 1', 'Type 2', 'Total', 'HP', 'Attack', 'Defense',
'Sp. Atk', 'Sp. Def', 'Speed'],
dtype='object')
print('第一屬性的種類數量:', set(df['Type 1']).__len__())
print(df['Type 1'].value_counts()[:3])
df['Type 1'].value_counts().index[:3]
#.sort_values(by='count',ascending=False)['Type 1'][0:3]
第一屬性的種類數量: 18
Water 105
Normal 93
Grass 66
Name: Type 1, dtype: int64
Index(['Water', 'Normal', 'Grass'], dtype='object')
print('多列去重 -- 求第一屬性和第二屬性的組合種類')
df_2 = df.drop_duplicates(['Type 1', 'Type 2'])
df_2.shape[0]
多列去重 -- 求第一屬性和第二屬性的組合種類
143
print('可以使用set做一個差集 -- 求尚未出現過的屬性組合')
type1_name_set = set(df['Type 1'])
type2_name_set = set(df['Type 2'])
all_type_pair, now_type_pair = set(), set()
for x in type1_name_set:
for y in type2_name_set:
all_type_pair.add((x, y))
for x,y in zip(df['Type 1'], df['Type 2']):
now_type_pair.add((x,y))
print('列印差集: ')
name_diff = all_type_pair.difference(now_type_pair)
print(len(name_diff), name_diff)
可以使用set做一個差集 -- 求尚未出現過的屬性組合
列印差集:
199 {('Fighting', 'Fighting'), ('Ghost', 'Ground'), ('Dragon', 'Ghost'), ('Grass', 'Dragon'), ('Flying', 'Electric'), ('Ice', 'Electric'), ('Dark', 'Fairy'), ('Grass', 'Grass'), ('Electric', 'Psychic'), ('Grass', 'Water'), ('Electric', 'Poison'), ('Bug', 'Psychic'), ('Grass', 'Bug'), ('Psychic', 'Psychic'), ('Normal', 'Poison'), ('Psychic', 'Normal'), ('Grass', 'Fire'), ('Steel', 'Dark'), ('Poison', 'Psychic'), ('Bug', 'Dragon'), ('Grass', 'Ghost'), ('Fairy', 'Fighting'), ('Psychic', 'Steel'), ('Poison', 'Normal'), ('Bug', 'Ice'), ('Ground', 'Normal'), ('Ghost', 'Fairy'), ('Dragon', 'Normal'), ('Poison', 'Steel'), ('Electric', 'Grass'), ('Electric', 'Water'), ('Psychic', 'Water'), ('Flying', 'Fighting'), ('Ice', 'Fighting'), ('Steel', 'Electric'), ('Bug', 'Bug'), ('Dragon', 'Steel'), ('Normal', 'Fighting'), ('Poison', 'Grass'), ('Ground', 'Grass'), ('Rock', 'Electric'), ('Ground', 'Water'), ('Fire', 'Grass'), ('Dragon', 'Grass'), ('Poison', 'Fire'), ('Dark', 'Electric'), ('Fighting', 'Rock'), ('Dragon', 'Water'), ('Ground', 'Fire'), ('Poison', 'Ghost'), ('Electric', 'Dark'), ('Psychic', 'Dark'), ('Fire', 'Fire'), ('Grass', 'Normal'), ('Fairy', 'Ice'), ('Fire', 'Ghost'), ('Electric', 'Ground'), ('Psychic', 'Ground'), ('Rock', 'Rock'), ('Fire', 'Dark'), ('Ghost', 'Electric'), ('Dragon', 'Dark'), ('Dark', 'Rock'), ('Flying', 'Ice'), ('Ice', 'Ice'), ('Ground', 'Ground'), ('Normal', 'Electric'), ('Fairy', 'Rock'), ('Psychic', 'Poison'), ('Bug', 'Normal'), ('Flying', 'Bug'), ('Poison', 'Poison'), ('Ground', 'Poison'), ('Fire', 'Poison'), ('Flying', 'Rock'), ('Ice', 'Rock'), ('Fighting', 'Dragon'), ('Dragon', 'Poison'), ('Fighting', 'Ice'), ('Normal', 'Rock'), ('Bug', 'Fairy'), ('Ghost', 'Fighting'), ('Electric', 'Fighting'), ('Steel', 'Ice'), ('Poison', 'Fairy'), ('Fighting', 'Grass'), ('Ground', 'Fairy'), ('Fighting', 'Bug'), ('Fairy', 'Psychic'), ('Fire', 'Fairy'), ('Dragon', 'Fairy'), ('Grass', 'Electric'), ('Fighting', 'Fire'), ('Fighting', 'Ghost'), ('Dragon', 'Fighting'), ('Bug', 'Dark'), ('Fairy', 'Dragon'), ('Fairy', 'Steel'), ('Flying', 'Flying'), ('Flying', 'Psychic'), ('Flying', 'Normal'), ('Ice', 'Normal'), ('Dark', 'Bug'), ('Fairy', 'Grass'), ('Ghost', 'Ice'), ('Ice', 'Dragon'), ('Fairy', 'Water'), ('Fairy', 'Bug'), ('Flying', 'Steel'), ('Electric', 'Electric'), ('Ice', 'Steel'), ('Psychic', 'Electric'), ('Normal', 'Dragon'), ('Normal', 'Ice'), ('Fairy', 'Fire'), ('Fairy', 'Ghost'), ('Poison', 'Electric'), ('Flying', 'Grass'), ('Ice', 'Grass'), ('Ghost', 'Bug'), ('Flying', 'Water'), ('Ice', 'Bug'), ('Fire', 'Electric'), ('Fighting', 'Poison'), ('Fighting', 'Normal'), ('Normal', 'Bug'), ('Ghost', 'Rock'), ('Flying', 'Fire'), ('Ice', 'Fire'), ('Water', 'Bug'), ('Electric', 'Rock'), ('Flying', 'Ghost'), ('Water', 'Fire'), ('Fairy', 'Ground'), ('Rock', 'Normal'), ('Flying', 'Dark'), ('Steel', 'Steel'), ('Fighting', 'Fairy'), ('Dark', 'Poison'), ('Dark', 'Normal'), ('Fighting', 'Water'), ('Dragon', 'Rock'), ('Fairy', 'Poison'), ('Flying', 'Ground'), ('Ground', 'Fighting'), ('Steel', 'Grass'), ('Fairy', 'Normal'), ('Steel', 'Water'), ('Steel', 'Bug'), ('Steel', 'Fire'), ('Ghost', 'Psychic'), ('Dark', 'Grass'), ('Flying', 'Poison'), ('Ice', 'Poison'), ('Dark', 'Water'), ('Ghost', 'Normal'), ('Rock', 'Fire'), ('Fairy', 'Fairy'), ('Normal', 'Normal'), ('Rock', 'Ghost'), ('Water', 'Normal'), ('Ghost', 'Steel'), ('Grass', 'Rock'), ('Electric', 'Dragon'), ('Fighting', 'Ground'), ('Psychic', 'Dragon'), ('Electric', 'Ice'), ('Psychic', 'Ice'), ('Normal', 'Steel'), ('Fighting', 'Electric'), ('Poison', 'Ice'), ('Flying', 'Fairy'), ('Ghost', 'Water'), ('Dark', 'Dark'), ('Ice', 'Fairy'), ('Ground', 'Ice'), ('Fire', 'Dragon'), ('Electric', 'Bug'), ('Fire', 'Ice'), ('Psychic', 'Bug'), ('Dragon', 'Dragon'), ('Fairy', 'Dark'), ('Water', 'Water'), ('Dark', 'Ground'), ('Electric', 'Fire'), ('Ghost', 'Ghost'), ('Steel', 'Poison'), ('Psychic', 'Rock'), ('Normal', 'Fire'), ('Steel', 'Normal'), ('Normal', 'Ghost'), ('Ground', 'Bug'), ('Rock', 'Poison'), ('Fire', 'Bug'), ('Poison', 'Rock'), ('Ice', 'Dark'), ('Dragon', 'Bug'), ('Normal', 'Dark'), ('Fairy', 'Electric')}
-
按照下述要求,構造 Series :
- (a) 取出物攻,超過 120 的替換為 high ,不足 50 的替換為 low ,否則設為 mid
- (b) 取出第一屬性,分別用 replace 和 apply 替換所有字母為大寫
- (c) 求每個妖怪六項能力的離差,即所有能力中偏離中位數最大的值,新增到 df 並從大到小排序
ret_a = df['Attack'].mask(df['Attack']>120, 'high')\
.mask(df['Attack']<50, 'low')\
.mask((50<=df['Attack'])&(df['Attack']<=120), 'mid')
ret_a
0 low
1 mid
2 mid
4 mid
5 mid
...
793 high
794 mid
795 mid
797 mid
799 mid
Name: Attack, Length: 721, dtype: object
# df['Type 1'].replace({i:str.upper(i) for i in df['Type 1'].unique()})
# 等價於
print(df['Type 1'])
for i in df['Type 1'].unique():
df['Type 1'].replace({i : str(i).upper()}, inplace=True)
df['Type 1']
0 Grass
1 Grass
2 Grass
4 Fire
5 Fire
...
793 Dark
794 Dragon
795 Rock
797 Psychic
799 Fire
Name: Type 1, Length: 721, dtype: object
0 GRASS
1 GRASS
2 GRASS
4 FIRE
5 FIRE
...
793 DARK
794 DRAGON
795 ROCK
797 PSYCHIC
799 FIRE
Name: Type 1, Length: 721, dtype: object
df['Type 1'].apply(lambda x : str(x).lower())
0 grass
1 grass
2 grass
4 fire
5 fire
...
793 dark
794 dragon
795 rock
797 psychic
799 fire
Name: Type 1, Length: 721, dtype: object
list_cols = ['HP', 'Attack', 'Defense', 'Sp. Atk', 'Sp. Def', 'Speed']
df['max_devision'] = \
df[list_cols].apply(lambda x : np.max((x-x.median()).abs()), 1)
df.sort_values('max_devision', ascending=False).head()
# | Name | Type 1 | Type 2 | Total | HP | Attack | Defense | Sp. Atk | Sp. Def | Speed | max_devision | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
230 | 213 | Shuckle | BUG | Rock | 505 | 20 | 10 | 230 | 10 | 230 | 5 | 215.0 |
121 | 113 | Chansey | NORMAL | NaN | 450 | 250 | 5 | 5 | 35 | 105 | 50 | 207.5 |
261 | 242 | Blissey | NORMAL | NaN | 540 | 255 | 10 | 10 | 75 | 135 | 55 | 190.0 |
217 | 202 | Wobbuffet | PSYCHIC | NaN | 405 | 190 | 33 | 58 | 33 | 58 | 33 | 144.5 |
223 | 208 | Steelix | STEEL | Ground | 510 | 75 | 85 | 200 | 55 | 65 | 30 | 130.0 |
六 練習
Ex2:指數加權視窗
- 作為擴張視窗的
ewm
視窗
在擴張視窗中,使用者可以使用各類函式進行歷史的累計指標統計,但這些內建的統計函式往往把視窗中的所有元素賦予了同樣的權重。事實上,可以給出不同的權重來賦給視窗中的元素,指數加權視窗就是這樣一種特殊的擴張視窗。
其中,最重要的引數是alpha
,它決定了預設情況下的視窗權重為\(w_i=(1−\alpha)^i,i\in\{0,1,...,t\}\),其中\(i=t\)表示當前元素,\(i=0\)表示序列的第一個元素。
從權重公式可以看出,離開當前值越遠則權重越小,若記原序列為\(x\),更新後的當前元素為\(y_t\),此時通過加權公式歸一化後可知:
\[\begin{split}y_t &=\frac{\sum_{i=0}^{t} w_i x_{t-i}}{\sum_{i=0}^{t} w_i} \\ &=\frac{x_t + (1 - \alpha)x_{t-1} + (1 - \alpha)^2 x_{t-2} + ... + (1 - \alpha)^{t} x_{0}}{1 + (1 - \alpha) + (1 - \alpha)^2 + ... + (1 - \alpha)^{t-1}}\\\end{split} \]對於Series
而言,可以用ewm
物件如下計算指數平滑後的序列:
np.random.seed(0)
s = pd.Series([-1, -1, -2, -2, -2])
s.head()
0 -1
1 -1
2 -2
3 -2
4 -2
dtype: int64
s.ewm(alpha=0.2).mean().head()
0 -1.000000
1 -1.000000
2 -1.409836
3 -1.609756
4 -1.725845
dtype: float64
請用expanding
視窗實現 s.ewm(alpha=0.2).mean()
。
def my_ewm_fun(lst_p, alpha=0.2):
lst = list(lst_p)
sums = 0
devide = 0
ret_lst = []
for idx in range(len(lst)-1, -1, -1):
x = lst[idx]
weight = (1-alpha)**(len(lst) - idx-1)
sums += x*(weight)
devide += weight
# print(x, x*(weight))
# TypeError: must be real number, not list
# print('**** ', sums)
# print('-------', sums, ' / ', devide)
return sums/devide
s.expanding().apply(my_ewm_fun).head()
def ewm_func(x, alpha=0.2):
win = (1-alpha)**np.arange(x.shape[0])[::-1]
res = (win*x).sum()/win.sum()
# print('**** ', (win*x))
# print((win*x).sum(), '/ weights:', win.sum())
return res
s.expanding().apply(ewm_func).head()
0 -1.000000
1 -1.000000
2 -1.409836
3 -1.609756
4 -1.725845
dtype: float64
- 作為滑動視窗的
ewm
視窗
從第1問中可以看到,ewm
作為一種擴張視窗的特例,只能從序列的第一個元素開始加權。現在希望給定一個限制視窗n
,只對包含自身最近的n
個視窗進行滑動加權平滑。請根據滑窗函式,給出新的wi
與yt
的更新公式,並通過rolling
視窗實現這一功能。
s.rolling(window=4).apply(my_ewm_fun).head()
0 NaN
1 NaN
2 NaN
3 -1.609756
4 -1.826558
dtype: float64
s.rolling(window=4).apply(ewm_func).head() # 無需對原函式改動
0 NaN
1 NaN
2 NaN
3 -1.609756
4 -1.826558
dtype: float64