第二章 pandas基礎(chǔ)

參考: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)換為 markdownlatex 語言吩翻,可以使用 to_markdownto_latex 函數(shù)兜看,此處需要安裝 tabulate 包。

print(df_csv.to_markdown())
print(df_csv.to_latex())

二狭瞎、基本數(shù)據(jù)結(jié)構(gòu)

pandas 中具有兩種基本的數(shù)據(jù)存儲結(jié)構(gòu)细移,存儲一維 valuesSeries 和存儲二維 valuesDataFrame,在這兩種結(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

DataFrameSeries 的基礎(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é)果分別為 SeriesDataFrame

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ù)

SeriesDataFrame 上定義了許多統(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
'''

duplicateddrop_duplicates 的功能類似永淌,但前者返回了是否為唯一值的布爾列表,其 keep 參數(shù)與后者一致佩耳。其返回的序列遂蛀,把重復(fù)元素設(shè)為 True ,否則為 False 干厚。 drop_duplicates 等價于把 duplicatedTrue 的對應(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
'''

邏輯替換

包括了 wheremask 渊迁,這兩個函數(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_valuessort_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+1rolling 方法等價代替:

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
  1. 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() #兩列可以用邏輯符號直接對比
  1. 對于 # 重復(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
  1. 按照下述要求,構(gòu)造 Series
  • 取出物攻默辨,超過120的替換為 high 生年,不足50的替換為 low ,否則設(shè)為 mid
答案:
df['Attack'].mask((50<=df['Attack']
)&(df['Attack']<=120), 'mid').head() #注意括號的寫法(...)&(...)
  • 取出第一屬性廓奕,分別用 replaceapply 替換所有字母為大寫
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)窗口

  1. 作為擴張窗口的 ewm 窗口

在擴張窗口中桌粉,用戶可以使用各類函數(shù)進行歷史的累計指標(biāo)統(tǒng)計蒸绩,但這些內(nèi)置的統(tǒng)計函數(shù)往往把窗口中的所有元素賦予了同樣的權(quán)重。事實上铃肯,可以給出不同的權(quán)重來賦給窗口中的元素患亿,指數(shù)加權(quán)窗口就是這樣一種特殊的擴張窗口。

其中押逼,最重要的參數(shù)是 alpha 步藕,它決定了默認(rèn)情況下的窗口權(quán)重為w_i = (1 - \alpha)^i, i\in \{0, 1, ..., t\} ,其中 i=t表示當(dāng)前元素挑格, i=0 表示序列的第一個元素咙冗。

從權(quán)重公式可以看出,離開當(dāng)前值越遠(yuǎn)則權(quán)重越小漂彤,若記原序列為 x 雾消,更新后的當(dāng)前元素為 y_t 灾搏,此時通過加權(quán)公式歸一化后可知:

\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}}\\\end{split}

對于 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
  1. 作為滑動窗口的 ewm 窗口

從第1問中可以看到狂窑, ewm 作為一種擴張窗口的特例,只能從序列的第一個元素開始加權(quán)∩H現(xiàn)在希望給定一個限制窗口 n 泉哈,只對包含自身的最近的 n 個元素作為窗口進行滑動加權(quán)平滑。請根據(jù)滑窗函數(shù)破讨,給出新的 w_iy_t 的更新公式丛晦,并通過 rolling 窗口實現(xiàn)這一功能。

w_i = (1 - \alpha)^i, i\in \{0, 1, ..., n\}

\begin{split}y_t &=\frac{\sum_{i=0}^{n-1} w_i x_{t-i}}{\sum_{i=0}^{n-1} w_i} \\ &=\frac{x_t + (1 - \alpha)x_{t-1} + (1 - \alpha)^2 x_{t-2} + ... + (1 - \alpha)^{n-1} x_{t-(n-1)}}{1 + (1 - \alpha) + (1 - \alpha)^2 + ... + (1 - \alpha)^{n-1}}\\\end{split}

s.rolling(window=4).apply(ewm_func).head() 
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末添忘,一起剝皮案震驚了整個濱河市采呐,隨后出現(xiàn)的幾起案子若锁,更是在濱河造成了極大的恐慌搁骑,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件又固,死亡現(xiàn)場離奇詭異仲器,居然都是意外死亡,警方通過查閱死者的電腦和手機仰冠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進店門乏冀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人洋只,你說我怎么就攤上這事辆沦。” “怎么了识虚?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵肢扯,是天一觀的道長。 經(jīng)常有香客問我担锤,道長蔚晨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任肛循,我火速辦了婚禮铭腕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘多糠。我一直安慰自己累舷,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布夹孔。 她就那樣靜靜地躺著笋粟,像睡著了一般怀挠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上害捕,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天绿淋,我揣著相機與錄音,去河邊找鬼尝盼。 笑死吞滞,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的盾沫。 我是一名探鬼主播裁赠,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼赴精!你這毒婦竟也來了佩捞?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤蕾哟,失蹤者是張志新(化名)和其女友劉穎一忱,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谭确,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡帘营,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了逐哈。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片芬迄。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖昂秃,靈堂內(nèi)的尸體忽然破棺而出禀梳,到底是詐尸還是另有隱情,我是刑警寧澤肠骆,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布算途,位于F島的核電站,受9級特大地震影響哗戈,放射性物質(zhì)發(fā)生泄漏郊艘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一唯咬、第九天 我趴在偏房一處隱蔽的房頂上張望纱注。 院中可真熱鬧,春花似錦胆胰、人聲如沸狞贱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瞎嬉。三九已至蝎毡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間氧枣,已是汗流浹背沐兵。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留便监,地道東北人扎谎。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像烧董,于是被迫代替她去往敵國和親毁靶。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內(nèi)容