pandas之常用基本函式學習筆記

風雪雲俠發表於2021-01-03

常用基本函式

為了進行舉例說明,在接下來的部分和其餘章節都將會使用一份 learn_pandas.csv 的虛擬資料集,它記錄了四所學校學生的體測個人資訊。

In [43]: df = pd.read_csv('data/learn_pandas.csv')

In [44]: df.columns
Out[44]: 
Index(['School', 'Grade', 'Name', 'Gender', 'Height', 'Weight', 'Transfer',
       'Test_Number', 'Test_Date', 'Time_Record'],
      dtype='object')

上述列名依次代表學校、年級、姓名、性別、身高、體重、是否為轉系生、體測場次、測試時間、1000米成績,本章只需使用其中的前七列。

In [45]: df = df[df.columns[:7]]

彙總函式

head, tail 函式分別表示返回表或者序列的前 n 行和後 n 行,其中 n 預設為5:

In [46]: df.head(2)
Out[46]: 
                          School     Grade            Name  Gender  Height  Weight Transfer
0  Shanghai Jiao Tong University  Freshman    Gaopeng Yang  Female   158.9    46.0        N
1              Peking University  Freshman  Changqiang You    Male   166.5    70.0        N

In [47]: df.tail(3)
Out[47]: 
                            School      Grade            Name  Gender  Height  Weight Transfer
197  Shanghai Jiao Tong University     Senior  Chengqiang Chu  Female   153.9    45.0        N
198  Shanghai Jiao Tong University     Senior   Chengmei Shen    Male   175.3    71.0        N
199            Tsinghua University  Sophomore     Chunpeng Lv    Male   155.7    51.0        N

info, describe 分別返回表的 資訊概況 和表中 數值列對應的主要統計量

In [48]: 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

In [49]: df.describe()
Out[49]: 
           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

特徵統計函式

在 Series 和 DataFrame 上定義了許多統計函式,最常見的是 sum, mean, median, var, std, max, min 。例如,選出身高和體重列進行演示:

In [50]: df_demo = df[['Height', 'Weight']]

In [51]: df_demo.mean()
Out[51]: 
Height    163.218033
Weight     55.015873
dtype: float64

In [52]: df_demo.max()
Out[52]: 
Height    193.9
Weight     89.0
dtype: float64

此外,需要介紹的是 quantile, count, idxmax 這三個函式,它們分別返回的是分位數、非缺失值個數、最大值對應的索引

In [53]: df_demo.quantile(0.75)
Out[53]: 
Height    167.5
Weight     65.0
Name: 0.75, dtype: float64

In [54]: df_demo.count()
Out[54]: 
Height    183
Weight    189
dtype: int64

In [55]: df_demo.idxmax() # idxmin是對應的函式
Out[55]: 
Height    193
Weight      2
dtype: int64

上面這些所有的函式,由於操作後返回的是標量,所以又稱為聚合函式,它們有一個公共引數 axis ,預設為0代表逐列聚合,如果設定為1則表示逐行聚合

In [56]: df_demo.mean(axis=1).head() # 在這個資料集上體重和身高的均值並沒有意義
Out[56]: 
0    102.45
1    118.25
2    138.95
3     41.00
4    124.00
dtype: float64

唯一值函式

對序列使用 unique 和 nunique 可以分別得到其唯一值組成的列表唯一值的個數

In [57]: df['School'].unique()
Out[57]: 
array(['Shanghai Jiao Tong University', 'Peking University',
       'Fudan University', 'Tsinghua University'], dtype=object)

In [58]: df['School'].nunique()
Out[58]: 4

value_counts 可以得到唯一值和其對應出現的頻數:

In [59]: df['School'].value_counts()
Out[59]: 
Tsinghua University              69
Shanghai Jiao Tong University    57
Fudan University                 40
Peking University                34
Name: School, dtype: int64

如果想要觀察多個列組合的唯一值,可以使用 drop_duplicates 。其中的關鍵引數是 keep ,預設值 first 表示每個組合保留第一次出現的所在行, last 表示保留最後一次出現的所在行, False 表示把所有重複組合所在的行剔除。

In [60]: df_demo = df[['Gender','Transfer','Name']]

In [61]: df_demo.drop_duplicates(['Gender', 'Transfer'])
Out[61]: 
    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

In [62]: df_demo.drop_duplicates(['Gender', 'Transfer'], keep='last')
Out[62]: 
     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

In [63]: df_demo.drop_duplicates(['Name', 'Gender'],
   ....:                      keep=False).head() # 保留只出現過一次的性別和姓名組合
   ....: 
Out[63]: 
   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

In [64]: df['School'].drop_duplicates() # 在Series上也可以使用
Out[64]: 
0    Shanghai Jiao Tong University
1                Peking University
3                 Fudan University
5              Tsinghua University
Name: School, dtype: object

此外,duplicateddrop_duplicates 的功能類似,但前者返回了是否為唯一值的布林列表,其 keep 引數與後者一致。其返回的序列,把重複元素設為 True ,否則為 False 。 drop_duplicates 等價於把 duplicatedTrue 的對應行剔除。

In [65]: df_demo.duplicated(['Gender', 'Transfer']).head()
Out[65]: 
0    False
1    False
2     True
3     True
4     True
dtype: bool

In [66]: df['School'].duplicated().head() # 在Series上也可以使用
Out[66]: 
0    False
1    False
2     True
3    False
4     True
Name: School, dtype: bool

替換函式

一般而言,替換操作是針對某一個列進行的,因此下面的例子都以 Series 舉例。 pandas 中的替換函式可以歸納為三類:對映替換、邏輯替換、數值替換。
其中對映替換包含 replace 方法、str.replace 方法以及 cat.codes 方法,此處介紹 replace 的用法。
在 replace 中,可以通過字典構造,或者傳入兩個列表來進行替換

In [67]: df['Gender'].replace({'Female':0, 'Male':1}).head()
Out[67]: 
0    0
1    1
2    1
3    0
4    1
Name: Gender, dtype: int64

In [68]: df['Gender'].replace(['Female', 'Male'], [0, 1]).head()
Out[68]: 
0    0
1    1
2    1
3    0
4    1
Name: Gender, dtype: int64

另外, replace 還有一種特殊的方向替換,指定 method 引數為 ffill 則為用前面一個最近的未被替換的值進行替換, bfill 則使用後面最近的未被替換的值進行替換。從下面的例子可以看到,它們的結果是不同的:

In [69]: s = pd.Series(['a', 1, 'b', 2, 1, 1, 'a'])

In [70]: s.replace([1, 2], method='ffill')
Out[70]: 
0    a
1    a
2    b
3    b
4    b
5    b
6    a
dtype: object

In [71]: s.replace([1, 2], method='bfill')
Out[71]: 
0    a
1    b
2    b
3    a
4    a
5    a
6    a
dtype: object

邏輯替換包括了 wheremask ,這兩個函式是完全對稱的: where 函式在傳入條件為 False 的對應行進行替換,而 mask 在傳入條件為 True 的對應行進行替換當不指定替換值時,替換為缺失值

In [72]: s = pd.Series([-1, 1.2345, 100, -50])

In [73]: s.where(s<0)
Out[73]: 
0    -1.0
1     NaN
2     NaN
3   -50.0
dtype: float64

In [74]: s.where(s<0, 100)
Out[74]: 
0     -1.0
1    100.0
2    100.0
3    -50.0
dtype: float64

In [75]: s.mask(s<0)
Out[75]: 
0         NaN
1      1.2345
2    100.0000
3         NaN
dtype: float64

In [76]: s.mask(s<0, -50)
Out[76]: 
0    -50.0000
1      1.2345
2    100.0000
3    -50.0000
dtype: float64

需要注意的是,傳入的條件只需是與被呼叫的 Series 索引一致的布林序列即可:

In [77]: s_condition= pd.Series([True,False,False,True],index=s.index)

In [78]: s.mask(s_condition, -50)
Out[78]: 
0    -50.0000
1      1.2345
2    100.0000
3    -50.0000
dtype: float64

數值替換包含了 round, abs, clip 方法,它們分別表示按照給定精度四捨五入、取絕對值和截斷:

In [79]: s = pd.Series([-1, 1.2345, 100, -50])

In [80]: s.round(2)
Out[80]: 
0     -1.00
1      1.23
2    100.00
3    -50.00
dtype: float64

In [81]: s.abs()
Out[81]: 
0      1.0000
1      1.2345
2    100.0000
3     50.0000
dtype: float64

In [82]: s.clip(0, 2) # 前兩個數分別表示上下截斷邊界
Out[82]: 
0    0.0000
1    1.2345
2    2.0000
3    0.0000
dtype: float64

在 clip 中,超過邊界的只能截斷為邊界值

排序函式

排序共有兩種方式,其一為值排序,其二為索引排序,對應的函式是 sort_valuessort_index

為了演示排序函式,下面先利用 set_index 方法把年級和姓名兩列作為索引:

In [83]: df_demo = df[['Grade', 'Name', 'Height',
   ....:               'Weight']].set_index(['Grade','Name'])
   ....: 

對身高進行排序,預設引數 ascending=True 為升序:

In [84]: df_demo.sort_values('Height').head()
Out[84]: 
                         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

In [85]: df_demo.sort_values('Height', ascending=False).head()
Out[85]: 
                        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

在排序中,經常遇到多列排序的問題,比如在體重相同的情況下,對身高進行排序,並且保持身高降序排列,體重升序排列:

In [86]: df_demo.sort_values(['Weight','Height'],ascending=[True,False]).head()
Out[86]: 
                       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

索引排序的用法和值排序完全一致,只不過元素的值在索引中,此時需要指定索引層的名字或者層號,用引數 level 表示。另外,需要注意的是字串的排列順序由字母順序決定

In [87]: df_demo.sort_index(level=['Grade','Name'],ascending=[True,False]).head()
Out[87]: 
                        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

apply方法

apply方法常用於 DataFrame 的行迭代或者列迭代,它的 axis 含義與統計聚合函式一致, apply 的引數往往是一個以序列為輸入的函式。例如對於.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 表示式使得書寫簡潔,這裡的 x 就指代被呼叫的 df_demo 表中逐個輸入的序列:

In [91]: df_demo.apply(lambda x:x.mean())
Out[91]: 
Height    163.218033
Weight     55.015873
dtype: float64

若指定 axis=1 ,那麼每次傳入函式的就是行元素組成的 Series ,其結果與之前的逐行均值結果一致。

In [92]: df_demo.apply(lambda x:x.mean(), axis=1).head()
Out[92]: 
0    102.45
1    118.25
2    138.95
3     41.00
4    124.00
dtype: float64

這裡再舉一個例子:mad 函式返回的是一個序列中偏離該序列均值的絕對值大小的均值,例如序列1,3,7,10中,均值為5.25,每一個元素偏離的絕對值為4.25,2.25,1.75,4.75,這個偏離序列的均值為3.25。現在利用 apply 計算升高和體重的 mad 指標:

In [93]: df_demo.apply(lambda x:(x-x.mean()).abs().mean())
Out[93]: 
Height     6.707229
Weight    10.391870
dtype: float64

這與使用內建的 mad 函式計算結果一致:

In [94]: df_demo.mad()
Out[94]: 
Height     6.707229
Weight    10.391870
dtype: float64

得益於傳入自定義函式的處理, apply 的自由度很高,但這是以效能為代價的。一般而言,使用 pandas 的內建函式處理和 apply 來處理同一個任務,其速度會相差較多,因此只有在確實存在自定義需求的情境下才考慮使用 apply 。

相關文章