參考:https://datawhalechina.github.io/joyful-pandas/build/html/%E7%9B%AE%E5%BD%95/ch2.html#id7
主要介紹讀取csv,excel.txt
文件
讀取csv:
df_csv = pd.read_csv("data/my_csv.csv")
df_csv
'''
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
'''
讀取txt
df_txt = pd.read_table('data/my_table.txt')
df_txt
'''
col1 col2 col3 col4
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
'''
讀取excel
df_excel = pd.read_excel('data/my_excel.xlsx')
df_excel
'''
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
'''
一些公共參數(shù)
- header=None: 第一行不作為列名,即第一行也作為數(shù)據(jù)
- index_col: 把某一列或幾列作為索引
- usecols: 讀取列的集合,默認(rèn)讀取所有的列
- parse_dates: 表示需要轉(zhuǎn)化為時間的列
- nrows: 讀取的數(shù)據(jù)行數(shù)
pd.read_table('data/my_table.txt', header=None)
'''
0 1 2 3
0 col1 col2 col3 col4
1 2 a 1.4 apple 2020/1/1
2 3 b 3.4 banana 2020/1/2
3 6 c 2.5 orange 2020/1/5
4 5 d 3.2 lemon 2020/1/7
'''
pd.read_csv('data/my_csv.csv', index_col=['col1', 'col2'])
'''
col3 col4 col5
col1 col2
2 a 1.4 apple 2020/1/1
3 b 3.4 banana 2020/1/2
6 c 2.5 orange 2020/1/5
5 d 3.2 lemon 2020/1/7
'''
pd.read_table('data/my_table.txt', usecols=['col1', 'col2']) #讀取前兩列
'''
col1 col2
0 2 a
1 3 b
2 6 c
3 5 d
'''
pd.read_csv('data/my_csv.csv', parse_dates=['col5'])
'''
col1 col2 col3 col4 col5
0 2 a 1.4 apple 2020-01-01
1 3 b 3.4 banana 2020-01-02
2 6 c 2.5 orange 2020-01-05
3 5 d 3.2 lemon 2020-01-07
'''
pd.read_excel('data/my_excel.xlsx', nrows=2) #讀取前兩行
'''
col1 col2 col3 col4 col5
0 2 a 1.4 apple 2020/1/1
1 3 b 3.4 banana 2020/1/2
'''
非公共參數(shù)
read_table的參數(shù)sep:使用戶可以自定義分割符號碉熄,進行 txt
數(shù)據(jù)的讀取
注意:sep是正則表達(dá)式矿微,同時需要指定引擎為python。
pd.read_table('data/my_table_special_sep.txt',
sep=' \|\|\|\| ', engine='python')
'''
col1 col2
0 TS This is an apple.
1 GQ My name is Bob.
2 WT Well done!
3 PT May I help you?
'''
2. 數(shù)據(jù)寫入
一般在數(shù)據(jù)寫入中俺驶,最常用的操作是把 index
設(shè)置為 False
,特別當(dāng)索引沒有特殊意義的時候,這樣的行為能把索引在保存的時候去除票从。特別是默認(rèn)讀取時,會自動加上0,1,2,3....的索引滨嘱,如上面幾個例子峰鄙,設(shè)為false之后,就可以不保存這些索引了太雨。
保存為csv或xlsx:
df_csv.to_csv('data/my_csv_saved.csv', index=False)
df_excel.to_excel('data/my_excel_saved.xlsx', index=False)
保存為txt
pandas
中沒有定義 to_table
函數(shù)吟榴,但是 to_csv
可以保存為 txt
文件,并且允許自定義分隔符囊扳,常用制表符 \t
分割:
df_txt.to_csv('data/my_txt_saved.txt', sep='\t', index=False)
如果想要把表格快速轉(zhuǎn)換為 markdown
和 latex
語言吩翻,可以使用 to_markdown
和 to_latex
函數(shù)兜看,此處需要安裝 tabulate
包。
print(df_csv.to_markdown())
print(df_csv.to_latex())
二狭瞎、基本數(shù)據(jù)結(jié)構(gòu)
pandas
中具有兩種基本的數(shù)據(jù)存儲結(jié)構(gòu)细移,存儲一維 values
的 Series
和存儲二維 values
的 DataFrame
,在這兩種結(jié)構(gòu)上定義了很多的屬性和方法熊锭。
1. Series(一維)
定義
由四個部分組成葫哗,分別是序列的值 data
、索引 index
球涛、存儲類型 dtype
劣针、序列的名字 name
。其中亿扁,索引也可以指定它的名字捺典,默認(rèn)為空。
s = pd.Series(data = [100, 'a', {'dic1':5}],
index = pd.Index(['id1', 20, 'third'], name='my_idx'),
dtype = 'object', #代表了一種混合類型从祝,正如例子中存儲了整數(shù)襟己、字符串以及 Python 的字典數(shù)據(jù)結(jié)構(gòu)。
name = 'my_name')
s
'''
my_idx
id1 100
20 a
third {'dic1': 5}
Name: my_name, dtype: object
'''
取出屬性:
s.values #array([100, 'a', {'dic1': 5}], dtype=object)
s.index #Index(['id1', 20, 'third'], dtype='object', name='my_idx')
s.dtype #dtype('O')
s.name #my_name
s.shape # .shape 可以獲取序列的長度:(3,)
如果想要取出單個索引對應(yīng)的值牍陌,可以通過 [index_item]
可以取出擎浴。
s['third'] #{'dic1': 5}
2. DataFrame
DataFrame
在 Series
的基礎(chǔ)上增加了列索引,一個數(shù)據(jù)框可以由二維的 data
與行列索引來構(gòu)造:
定義
不常用的定義方式:按行元素定義
data = [[1, 'a', 1.2], [2, 'b', 2.2], [3, 'c', 3.2]]
df = pd.DataFrame(data = data,
index = ['row_%d'%i for i in range(3)],
columns=['col_0', 'col_1', 'col_2'])
'''
col_0 col_1 col_2
row_0 1 a 1.2
row_1 2 b 2.2
row_2 3 c 3.2
'''
常用的定義方式:采用從列索引名到數(shù)據(jù)的映射來構(gòu)造數(shù)據(jù)框毒涧,同時再加上行索引:
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)])
'''
col_0 col_1 col_2
row_0 1 a 1.2
row_1 2 b 2.2
row_2 3 c 3.2
'''
取出值:
由于這種映射關(guān)系贮预,在 DataFrame
中可以用 [col_name]
與 [col_list]
來取出相應(yīng)的列與由多個列組成的表,結(jié)果分別為 Series
和 DataFrame
:
df['col_0']
'''
會顯示行索引
row_0 1
row_1 2
row_2 3
Name: col_0, dtype: int64
'''
df[['col_0', 'col_1']]
'''
col_0 col_1
row_0 1 a
row_1 2 b
row_2 3 c
'''
與 Series
類似契讲,在數(shù)據(jù)框中同樣可以取出相應(yīng)的屬性:
df.values
'''
array([[1, 'a', 1.2],
[2, 'b', 2.2],
[3, 'c', 3.2]], dtype=object)
'''
df.index
'''
Index(['row_0', 'row_1', 'row_2'], dtype='object')
'''
df.columns #Index(['col_0', 'col_1', 'col_2'], dtype='object')
df.dtypes # 返回的是值為相應(yīng)列數(shù)據(jù)類型的Series
'''
col_0 int64
col_1 object
col_2 float64
dtype: object
'''
df.shape #(3, 3)
轉(zhuǎn)置
通過 .T
可以把 DataFrame
進行轉(zhuǎn)置:
df.T
'''
row_0 row_1 row_2
col_0 1 2 3
col_1 a b c
col_2 1.2 2.2 3.2
'''
三仿吞、常用基本函數(shù)
練習(xí)集:
df = pd.read_csv('data/learn_pandas.csv')
df = df[df.columns[:7]] #只取前7列
1. 匯總函數(shù)
head, tail 函數(shù)
分別表示返回表或者序列的前 n
行和后 n
行,其中 n
默認(rèn)為5:
df.head(2)
df.tail(3)
info, describe函數(shù)
分別返回表的 信息概況 和表中 數(shù)值列對應(yīng)的主要統(tǒng)計量 :
df.info() #信息概況
'''
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 200 entries, 0 to 199
Data columns (total 7 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 School 200 non-null object
1 Grade 200 non-null object
2 Name 200 non-null object
3 Gender 200 non-null object
4 Height 183 non-null float64
5 Weight 189 non-null float64
6 Transfer 188 non-null object
dtypes: float64(2), object(5)
memory usage: 11.1+ KB
'''
df.describe() #數(shù)值列對應(yīng)的主要統(tǒng)計量
'''
Height Weight
count 183.000000 189.000000
mean 163.218033 55.015873
std 8.608879 12.824294
min 145.400000 34.000000
25% 157.150000 46.000000
50% 161.900000 51.000000
75% 167.500000 65.000000
max 193.900000 89.000000
'''
更全面的數(shù)據(jù)匯總
info, describe
只能實現(xiàn)較少信息的展示捡偏,如果想要對一份數(shù)據(jù)集進行全面且有效的觀察唤冈,特別是在列較多的情況下,推薦使用 pandas-profiling 包银伟,它將在第十一章被再次提到你虹。
2. 特征統(tǒng)計函數(shù)
在 Series
和 DataFrame
上定義了許多統(tǒng)計函數(shù),最常見的是 sum, mean, median, var, std, max,min
彤避。例如傅物,選出身高和體重列進行演示:
df_demo = df[['Height', 'Weight']]
df_demo.mean()#平均值
'''
Height 163.218033
Weight 55.015873
dtype: float64
'''
df_demo.max()
'''
Height 193.9
Weight 89.0
dtype: float64
'''
此外,需要介紹的是 quantile, count, idxmax
這三個函數(shù)忠藤,它們分別返回的是分位數(shù)挟伙、非缺失值個數(shù)楼雹、最大值對應(yīng)的索引:
df_demo.quantile(0.75)
'''
Height 167.5
Weight 65.0
Name: 0.75, dtype: float64
'''
df_demo.count() #缺失值:數(shù)值為NaN
'''
Height 183
Weight 189
dtype: int64
'''
df_demo.idxmax() # 最大值的索引
'''
Height 193
Weight 2
dtype: int64
'''
上面這些所有的函數(shù)模孩,由于操作后返回的是標(biāo)量尖阔,所以又稱為聚合函數(shù),它們有一個公共參數(shù) axis
榨咐,默認(rèn)為0代表逐列聚合介却,如果設(shè)置為1則表示逐行聚合:
df_demo.mean(axis=1).head() # 前五行的平均值;在這個數(shù)據(jù)集上體重和身高的均值并沒有意義
'''
0 102.45
1 118.25
2 138.95
3 41.00
4 124.00
'''
3. 唯一值函數(shù)
unique函數(shù)和nunique函數(shù)
分別得到其唯一值組成的列表和唯一值的個數(shù):
df['School'].unique()
'''
array(['Shanghai Jiao Tong University', 'Peking University',
'Fudan University', 'Tsinghua University'], dtype=object)
'''
df['School'].nunique() #4 4個唯一值
value_counts
得到唯一值和其對應(yīng)出現(xiàn)的頻數(shù)
df['School'].value_counts()
'''
Tsinghua University 69
Shanghai Jiao Tong University 57
Fudan University 40
Peking University 34
Name: School, dtype: int64
'''
drop_duplicates
其中的關(guān)鍵參數(shù)是 keep
块茁,默認(rèn)值 first
表示每個組合保留第一次出現(xiàn)的所在行齿坷, last
表示保留最后一次出現(xiàn)的所在行, False
表示把所有重復(fù)組合所在的行剔除数焊。
df_demo = df[['Gender', "Transfer", "Name"]]
df_demo.drop_duplicates(['Gender', 'Transfer']) #默認(rèn)保留第一次出現(xiàn)的行
'''
Gender Transfer Name
0 Female N Gaopeng Yang
1 Male N Changqiang You
12 Female NaN Peng You
21 Male NaN Xiaopeng Shen
36 Male Y Xiaojuan Qin
43 Female Y Gaoli Feng
'''
df_demo.drop_duplicates(['Gender', 'Transfer'], keep='last') #保留最后一次出現(xiàn)的所在行
'''
Gender Transfer Name
147 Male NaN Juan You
150 Male Y Chengpeng You
169 Female Y Chengquan Qin
194 Female NaN Yanmei Qian
197 Female N Chengqiang Chu
199 Male N Chunpeng Lv
'''
df_demo.drop_duplicates(['Name', 'Gender'],
keep=False).head() # 保留只出現(xiàn)過一次的性別和姓名組合
'''
Gender Transfer Name
0 Female N Gaopeng Yang
1 Male N Changqiang You
2 Male N Mei Sun
4 Male N Gaojuan You
5 Female N Xiaoli Qian
'''
df['School'].drop_duplicates() # 在Series上也可以使用
'''
0 Shanghai Jiao Tong University
1 Peking University
3 Fudan University
5 Tsinghua University
Name: School, dtype: object
'''
duplicated
和 drop_duplicates
的功能類似永淌,但前者返回了是否為唯一值的布爾列表,其 keep
參數(shù)與后者一致佩耳。其返回的序列遂蛀,把重復(fù)元素設(shè)為 True
,否則為 False
干厚。 drop_duplicates
等價于把 duplicated
為 True
的對應(yīng)行剔除李滴。
df_demo.duplicated(['Gender', 'Transfer']).head()
'''
0 False
1 False
2 True
3 True
4 True
dtype: bool
'''
df_demo.duplicated(['Gender', 'Transfer'],keep='last').head()
'''
0 True
1 True
2 True
3 True
4 True
'''
df['School'].duplicated().head() # 在Series上也可以使用
'''
0 False
1 False
2 True
3 False
4 True
Name: School, dtype: bool
'''
4. 替換函數(shù)
一般而言,替換操作是針對某一個列進行的蛮瞄,因此下面的例子都以 Series
舉例所坯。
pandas
中的替換函數(shù)可以歸納為三類:映射替換、邏輯替換挂捅、數(shù)值替換芹助。
映射替換 replace
映射替換包含 replace
方法、第八章中的 str.replace
方法以及第九章中的 cat.codes
方法闲先,此處介紹 replace
的用法周瞎。
在 replace
中,可以通過字典構(gòu)造饵蒂,或者傳入兩個列表來進行替換:
df['Gender'].replace({'Female':0, 'Male':1}).head() #對原來的數(shù)據(jù)沒有影響
'''
0 0
1 1
2 1
3 0
4 1
Name: Gender, dtype: int64
'''
df['Gender'].replace(['Female', 'Male'], [0, 1]).head()#跟上面的效果一樣
'''
0 0
1 1
2 1
3 0
4 1
'''
另外声诸, replace
還有一種特殊的方向替換,指定 method
參數(shù)為 ffill
則為用前面一個最近的未被替換的值進行替換退盯, bfill
則使用后面最近的未被替換的值進行替換彼乌。從下面的例子可以看到,它們的結(jié)果是不同的:
s = pd.Series(['a', 1, 'b', 2, 1, 1, 'a'])
s.replace([1, 2], method='ffill') #用前面一個最近的未被替換的值進行替換
'''
0 a
1 a
2 b
3 b
4 b
5 b
6 a
dtype: object
'''
s.replace([1, 2], method='bfill') #使用后面最近的未被替換的值進行替換
'''
0 a
1 b
2 b
3 a
4 a
5 a
6 a
dtype: object
'''
邏輯替換
包括了 where
和 mask
渊迁,這兩個函數(shù)是完全對稱的: where
函數(shù)在傳入條件為 False
的對應(yīng)行進行替換慰照,而 mask
在傳入條件為 True
的對應(yīng)行進行替換,當(dāng)不指定替換值時琉朽,替換為缺失值毒租。
s = pd.Series([-1, 1.2345, 100, -50])
s.where(s<0)#用缺失值替換
'''
0 -1.0
1 NaN
2 NaN
3 -50.0
'''
s.where(s<0, 100)#替換不符合條件的
'''
0 -1.0
1 100.0
2 100.0
3 -50.0
'''
s.mask(s<0) #用缺失值替換
'''
0 NaN
1 1.2345
2 100.0000
3 NaN
'''
s.mask(s<0, -50) #替換符合條件的
'''
0 -50.0000
1 1.2345
2 100.0000
3 -50.0000
'''
傳入的條件只需是與被調(diào)用的 Series
索引一致的布爾序列即可:
s_condition= pd.Series([True,False,False,True],index=s.index)
s.mask(s_condition, -50)
'''
0 -50.0000
1 1.2345
2 100.0000
3 -50.0000
'''
數(shù)值替換
包含了 round, abs, clip
方法,它們分別表示按照給定精度四舍五入箱叁、取絕對值和截斷:
s = pd.Series([-1, 1.2345, 100, -50])
s.round(2)
'''
0 -1.00
1 1.23
2 100.00
3 -50.00
dtype: float64
'''
s.abs()
'''
0 1.0000
1 1.2345
2 100.0000
3 50.0000
dtype: float64
'''
s.clip(0, 2) # 前兩個數(shù)分別表示上下截斷邊界
'''
0 0.0000
1 1.2345
2 2.0000
3 0.0000
dtype: float64
'''
練一練
在
clip
中墅垮,超過邊界的只能截斷為邊界值惕医,如果要把超出邊界的替換為自定義的值,應(yīng)當(dāng)如何做算色?
s.mask(s<0,11).mask(s>2,11)
5. 排序函數(shù)
排序共有兩種方式抬伺,其一為值排序,其二為索引排序灾梦,對應(yīng)的函數(shù)是 sort_values
和 sort_index
峡钓。
下面先利用 set_index
方法把年級和姓名兩列作為索引
df_demo = df[['Grade', 'Name', 'Height',
'Weight']].set_index(['Grade','Name'])
值排序
對身高進行排序,默認(rèn)參數(shù) ascending=True
為升序:
df_demo.sort_values('Height').head()
'''
Height Weight
Grade Name
Junior Xiaoli Chu 145.4 34.0
Senior Gaomei Lv 147.3 34.0
Sophomore Peng Han 147.8 34.0
Senior Changli Lv 148.7 41.0
Sophomore Changjuan You 150.5 40.0
'''
df_demo.sort_values('Height', ascending=False).head()
'''
Height Weight
Grade Name
Senior Xiaoqiang Qin 193.9 79.0
Mei Sun 188.9 89.0
Gaoli Zhao 186.5 83.0
Freshman Qiang Han 185.3 87.0
Senior Qiang Zheng 183.9 87.0
'''
在排序中若河,經(jīng)常遇到多列排序的問題能岩,比如在體重相同的情況下,對身高進行排序萧福,并且保持身高降序排列捧灰,體重升序排列:
df_demo.sort_values(['Weight','Height'],ascending=[True,False]).head()
'''
Height Weight
Grade Name
Sophomore Peng Han 147.8 34.0
Senior Gaomei Lv 147.3 34.0
Junior Xiaoli Chu 145.4 34.0
Sophomore Qiang Zhou 150.5 36.0
Freshman Yanqiang Xu 152.4 38.0
'''
索引排序
索引排序的用法和值排序完全一致,只不過元素的值在索引中统锤,此時需要指定索引層的名字或者層號毛俏,用參數(shù) level
表示。另外饲窿,需要注意的是字符串的排列順序由字母順序決定煌寇。
df_demo.sort_index(level=['Grade','Name'],ascending=[True,False]).head()
'''
Height Weight
Grade Name
Freshman Yanquan Wang 163.5 55.0
Yanqiang Xu 152.4 38.0
Yanqiang Feng 162.3 51.0
Yanpeng Lv NaN 65.0
Yanli Zhang 165.1 52.0
'''
6. apply方法
apply
方法常用于 DataFrame
的行迭代或者列迭代,它的 axis
含義與第2小節(jié)中的統(tǒng)計聚合函數(shù)一致逾雄, apply
的參數(shù)往往是一個以序列為輸入的函數(shù)阀溶。例如對于 .mean()
,使用 apply
可以如下地寫出:
In [88]: df_demo = df[['Height', 'Weight']]
In [89]: def my_mean(x):
....: res = x.mean()
....: return res
....:
In [90]: df_demo.apply(my_mean)
Out[90]:
Height 163.218033
Weight 55.015873
dtype: float64
同樣的鸦泳,可以利用 lambda
表達(dá)式使得書寫簡潔银锻,這里的 x
就指代被調(diào)用的 df_demo
表中逐個輸入的序列:
In [91]: df_demo.apply(lambda x:x.mean())
Out[91]:
Height 163.218033
Weight 55.015873
dtype: float64
得益于傳入自定義函數(shù)的處理,
apply
的自由度很高做鹰,但這是以性能為代價的击纬。一般而言,使用pandas
的內(nèi)置函數(shù)處理和apply
來處理同一個任務(wù)钾麸,其速度會相差較多更振,因此只有在確實存在自定義需求的情境下才考慮使用apply
。
四饭尝、窗口對象
pandas
中有3類窗口肯腕,分別是滑動窗口 rolling
、擴張窗口 expanding
以及指數(shù)加權(quán)窗口 ewm
钥平。需要說明的是实撒,以日期偏置為窗口大小的滑動窗口將在第十章討論,指數(shù)加權(quán)窗口見本章練習(xí)。
1. 滑窗對象
要使用滑窗函數(shù)知态,就必須先要對一個序列使用 .rolling
得到滑窗對象捷兰,其最重要的參數(shù)為窗口大小 window
。
In [95]: s = pd.Series([1,2,3,4,5])
In [96]: roller = s.rolling(window = 3)
In [97]: roller
Out[97]: Rolling [window=3,center=False,axis=0]
在得到了滑窗對象后肴甸,能夠使用相應(yīng)的聚合函數(shù)進行計算,需要注意的是窗口包含當(dāng)前行所在的元素囚巴,例如在第四個位置進行均值運算時原在,應(yīng)當(dāng)計算(2+3+4)/3,而不是(1+2+3)/3:
In [98]: roller.mean()
Out[98]:
0 NaN
1 NaN
2 2.0 # 1,2,3
3 3.0 # 2,3,4
4 4.0 # 3,4,5
dtype: float64
In [99]: roller.sum()
Out[99]:
0 NaN
1 NaN
2 6.0
3 9.0
4 12.0
dtype: float64
對于滑動相關(guān)系數(shù)或滑動協(xié)方差的計算彤叉,可以如下寫出:
In [100]: s2 = pd.Series([1,2,6,16,30])
In [101]: roller.cov(s2)
Out[101]:
0 NaN
1 NaN
2 2.5
3 7.0
4 12.0
dtype: float64
In [102]: roller.corr(s2)
Out[102]:
0 NaN
1 NaN
2 0.944911
3 0.970725
4 0.995402
dtype: float64
此外庶柿,還支持使用 apply
傳入自定義函數(shù),其傳入值是對應(yīng)窗口的 Series
秽浇,例如上述的均值函數(shù)可以等效表示:
In [103]: roller.apply(lambda x:x.mean())
Out[103]:
0 NaN
1 NaN
2 2.0
3 3.0
4 4.0
dtype: float64
shift, diff, pct_change
是一組類滑窗函數(shù)浮庐,它們的公共參數(shù)為 periods=n
,默認(rèn)為1柬焕,分別表示取向前第 n
個元素的值审残、與向前第 n
個元素做差(與 Numpy
中不同,后者表示 n
階差分)斑举、與向前第 n
個元素相比計算增長率搅轿。這里的 n
可以為負(fù),表示反方向的類似操作富玷。
In [104]: s = pd.Series([1,3,6,10,15])
In [105]: s.shift(2) #取向前第 n 個元素的值
Out[105]:
0 NaN
1 NaN
2 1.0
3 3.0
4 6.0
dtype: float64
In [106]: s.diff(3) #與向前第 n 個元素做差
Out[106]:
0 NaN
1 NaN
2 NaN
3 9.0
4 12.0
dtype: float64
In [107]: s.pct_change() #與向前第n個元素相比計算增長率璧坟。
Out[107]:
0 NaN
1 2.000000
2 1.000000
3 0.666667
4 0.500000
dtype: float64
In [108]: s.shift(-1)
Out[108]:
0 3.0
1 6.0
2 10.0
3 15.0
4 NaN
dtype: float64
In [109]: s.diff(-2)
Out[109]:
0 -5.0
1 -7.0
2 -9.0
3 NaN
4 NaN
dtype: float64
將其視作類滑窗函數(shù)的原因是,它們的功能可以用窗口大小為 n+1
的 rolling
方法等價代替:
In [110]: s.rolling(3).apply(lambda x:list(x)[0]) # s.shift(2)
Out[110]:
0 NaN
1 NaN
2 1.0
3 3.0
4 6.0
dtype: float64
In [111]: s.rolling(4).apply(lambda x:list(x)[-1]-list(x)[0]) # s.diff(3)
Out[111]:
0 NaN
1 NaN
2 NaN
3 9.0
4 12.0
dtype: float64
In [112]: def my_pct(x):
.....: L = list(x)
.....: return L[-1]/L[0]-1
.....:
In [113]: s.rolling(2).apply(my_pct) # s.pct_change()
Out[113]:
0 NaN
1 2.000000
2 1.000000
3 0.666667
4 0.500000
dtype: float64
練一練
rolling
對象的默認(rèn)窗口方向都是向前的赎懦,某些情況下用戶需要向后的窗口雀鹃,例如對1,2,3設(shè)定向后窗口為2的sum
操作,結(jié)果為3,5,NaN励两,此時應(yīng)該如何實現(xiàn)向后的滑窗操作黎茎?
s = pd.Series([1,2,3])
s.rolling(2).sum().shift(-1)
2. 擴張窗口
擴張窗口又稱累計窗口
,可以理解為一個動態(tài)長度的窗口当悔,其窗口的大小就是從序列開始處到具體操作的對應(yīng)位置工三,其使用的聚合函數(shù)會作用于這些逐步擴張的窗口上。具體地說先鱼,設(shè)序列為a1, a2, a3, a4俭正,則其每個位置對應(yīng)的窗口即[a1]、[a1, a2]焙畔、[a1, a2, a3]掸读、[a1, a2, a3, a4]。
In [114]: s = pd.Series([1, 3, 6, 10])
In [115]: s.expanding().mean()
Out[115]:
0 1.000000 #1
1 2.000000 #1,4
2 3.333333 #1,3,6
3 5.000000 #1,3,6,10
dtype: float64
練一練
cummax, cumsum, cumprod
函數(shù)是典型的類擴張窗口函數(shù),請使用expanding
對象依次實現(xiàn)它們儿惫。
s = pd.Series([1, 3, 6, 10])
s.expanding().max()
s.expanding().sum()
def my_prod(x):
L = list(x)
prod = 1
for i in L:
prod *= i
return prod
s.expanding().apply(my_prod)
五澡罚、練習(xí)
Ex1:口袋妖怪?jǐn)?shù)據(jù)集
現(xiàn)有一份口袋妖怪的數(shù)據(jù)集,下面進行一些背景說明:
-
#
代表全國圖鑒編號肾请,不同行存在相同數(shù)字則表示為該妖怪的不同狀態(tài) - 妖怪具有單屬性和雙屬性兩種留搔,對于單屬性的妖怪,
Type 2
為缺失值 -
Total, HP, Attack, Defense, Sp. Atk, Sp. Def, Speed
分別代表種族值铛铁、體力隔显、物攻、防御饵逐、特攻括眠、特防、速度倍权,其中種族值為后6項之和
In [116]: df = pd.read_csv('data/pokemon.csv')
In [117]: df.head(3)
Out[117]:
# Name Type 1 Type 2 Total HP Attack Defense Sp. Atk Sp. Def Speed
0 1 Bulbasaur Grass Poison 318 45 49 49 65 65 45
1 2 Ivysaur Grass Poison 405 60 62 63 80 80 60
2 3 Venusaur Grass Poison 525 80 82 83 100 100 80
- 對
HP, Attack, Defense, Sp. Atk, Sp. Def, Speed
進行加總敏释,驗證是否為Total
值外傅。
series1 = df[df.columns[5:]].sum(axis=1)
series2 = df[df.columns[4]]
(series2-series1).value_counts()
'''
0 800 //確實都是total值
'''
答案:
(df[['HP', 'Attack', 'Defense', 'Sp. Atk', 'Sp. Def', 'Speed']].sum(1)!=df['Total']).mean() #兩列可以用邏輯符號直接對比
- 對于
#
重復(fù)的妖怪只保留第一條記錄召庞,解決以下問題:
- 求第一屬性的種類數(shù)量和前三多數(shù)量對應(yīng)的種類
#第一屬性的種類數(shù)量
df[df.columns[2]].drop_duplicates(keep="first").shape
'''
(18,)
'''
答案:
dp_dup = df.drop_duplicates('#', keep='first')
dp_dup['Type 1'].nunique()
'''
18
'''
#前三多數(shù)量對應(yīng)的種類
df[df.columns[0]].value_counts(ascending=False).head(3)
'''
479 6
386 4
711 4
'''
答案:
dp_dup = df.drop_duplicates('#', keep='first')
dp_dup['Type 1'].value_counts().index[:3]
- 求第一屬性和第二屬性的組合種類
df = pd.read_csv('data/pokemon.csv')
df.drop_duplicates(['Type 1','Type 2'])
- 求尚未出現(xiàn)過的屬性組合
答案:使用zip打包兩列破镰,set.difference函數(shù)可以對比兩個set
In [36]: L_full = [i+' '+j for i in df['Type 1'].unique() for j in (
....: df['Type 1'].unique().tolist() + [''])]
....:
In [37]: L_part = [i+' '+j for i, j in zip(df['Type 1'], df['Type 2'
....: ].replace(np.nan, ''))]
....:
In [38]: res = set(L_full).difference(set(L_part))
In [39]: len(res)
Out[39]: 188
- 按照下述要求,構(gòu)造
Series
:
- 取出物攻默辨,超過120的替換為
high
生年,不足50的替換為low
,否則設(shè)為mid
答案:
df['Attack'].mask((50<=df['Attack']
)&(df['Attack']<=120), 'mid').head() #注意括號的寫法(...)&(...)
- 取出第一屬性廓奕,分別用
replace
和apply
替換所有字母為大寫
df['Type 1'].apply(lambda x:x.upper())
df['Type 1'].replace({i:str.upper(i) for i in df['Type 1'
].unique()})
- 求每個妖怪六項能力的離差抱婉,即所有能力中偏離中位數(shù)最大的值,添加到
df
并從大到小排序
答案:
x.median:中位數(shù)
df['Deviation'] 可以創(chuàng)建一列并添加到原來的frame里
In [43]: df['Deviation'] = df[['HP', 'Attack', 'Defense', 'Sp. Atk', 'Sp. Def', 'Speed']].apply(lambda x:np.max((x-x.median()).abs()), 1)
In [44]: df.sort_values('Deviation', ascending=False).head()
Out[44]:
# Name Type 1 Type 2 Total HP Attack Defense Sp. Atk Sp. Def Speed Deviation
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
333 306 AggronMega Aggron Steel NaN 630 70 140 230 60 80 50 155.0
224 208 SteelixMega Steelix Steel Ground 610 75 125 230 55 95 30 145.0
Ex2:指數(shù)加權(quán)窗口
- 作為擴張窗口的
ewm
窗口
在擴張窗口中桌粉,用戶可以使用各類函數(shù)進行歷史的累計指標(biāo)統(tǒng)計蒸绩,但這些內(nèi)置的統(tǒng)計函數(shù)往往把窗口中的所有元素賦予了同樣的權(quán)重。事實上铃肯,可以給出不同的權(quán)重來賦給窗口中的元素患亿,指數(shù)加權(quán)窗口就是這樣一種特殊的擴張窗口。
其中押逼,最重要的參數(shù)是 alpha
步藕,它決定了默認(rèn)情況下的窗口權(quán)重為 ,其中
表示當(dāng)前元素挑格,
表示序列的第一個元素咙冗。
從權(quán)重公式可以看出,離開當(dāng)前值越遠(yuǎn)則權(quán)重越小漂彤,若記原序列為 x
雾消,更新后的當(dāng)前元素為 灾搏,此時通過加權(quán)公式歸一化后可知:
對于 Series
而言,可以用 ewm
對象如下計算指數(shù)平滑后的序列:
In [118]: np.random.seed(0)
In [119]: s = pd.Series(np.random.randint(-1,2,30).cumsum())
In [120]: s.head()
Out[120]:
0 -1
1 -1
2 -2
3 -2
4 -2
dtype: int32
In [121]: s.ewm(alpha=0.2).mean().head()
Out[121]:
0 -1.000000
1 -1.000000
2 -1.409836
3 -1.609756
4 -1.725845
dtype: float64
請用 expanding
窗口實現(xiàn)立润。
np.random.seed(0)
s = pd.Series(np.random.randint(-1,2,30).cumsum())
alpha = 0.2
def my_func(x):
W=[]
up = 0
for index,value in enumerate(x):
W.append((1-alpha)**index)
up += x[len(x)-index-1] * W[index]
return up/sum(W)
s.expanding().apply(my_func)
'''
0 -1.000000
1 -1.000000
2 -1.409836
3 -1.609756
4 -1.725845
5 -1.529101
6 -1.648273
...
'''
答案:
def ewm_func(x, alpha=0.2):
win = (1-alpha)**np.arange(x.shape[0])[::-1]#從后向前取元素
res = (win*x).sum()/win.sum()
return res
- 作為滑動窗口的
ewm
窗口
從第1問中可以看到狂窑, ewm
作為一種擴張窗口的特例,只能從序列的第一個元素開始加權(quán)∩H現(xiàn)在希望給定一個限制窗口 n
泉哈,只對包含自身的最近的 n
個元素作為窗口進行滑動加權(quán)平滑。請根據(jù)滑窗函數(shù)破讨,給出新的 與
的更新公式丛晦,并通過
rolling
窗口實現(xiàn)這一功能。
s.rolling(window=4).apply(ewm_func).head()