Pandas中文官档~基础用法3

作者: 呆鸟的简书 | 来源:发表于2019-10-18 16:59 被阅读0次

    呆鸟云:“觉得有用,就请点个赞,哈哈”

    函数应用

    不管是为 pandas 对象应用自定义函数,还是应用其它第三方函数,都离不开以下三种方法。用哪种方法取决于操作的对象是 DataFrameSeries ,是行或列,还是元素。

    1. 表级函数应用:pipe()

    2. 行列级函数应用: apply()

    3. 聚合 API: agg()transform()

    4. 元素级函数应用:applymap()

    表级函数应用

    虽然可以把 DataFrameSeries 传递给函数。不过,通过链式调用函数时,最好使用 pipe() 方法。对比以下两种方式:

    # f, g, and h are functions taking and returning ``DataFrames``
    >>> f(g(h(df), arg1=1), arg2=2, arg3=3)
    

    下列代码与上述代码等效

    >>> (df.pipe(h)
    ...    .pipe(g, arg1=1)
    ...    .pipe(f, arg2=2, arg3=3))
    

    pandas 鼓励使用第二种方式,即链式方法。在链式方法中调用自定义函数或第三方支持库函数时,用 pipe 更容易,与用 pandas 自身方法一样。

    上例中,fgh 这几个函数都把 DataFrame 当作首位参数。要是想把数据作为第二个参数,该怎么办?本例中,pipe 为元组 (callable,data_keyword)形式。.pipeDataFrame 作为元组里指定的参数。

    下例用 statsmodels 拟合回归。该 API 先接收一个公式,DataFrame 是第二个参数,data。要传递函数,则要用pipe 接收关键词对 (sm.ols,'data')。

    In [138]: import statsmodels.formula.api as sm
    
    In [139]: bb = pd.read_csv('data/baseball.csv', index_col='id')
    
    In [140]: (bb.query('h > 0')
       .....:    .assign(ln_h=lambda df: np.log(df.h))
       .....:    .pipe((sm.ols, 'data'), 'hr ~ ln_h + year + g + C(lg)')
       .....:    .fit()
       .....:    .summary()
       .....:  )
       .....: 
    Out[140]: 
    <class 'statsmodels.iolib.summary.Summary'>
    """
                                OLS Regression Results                            
    ==============================================================================
    Dep. Variable:                     hr   R-squared:                       0.685
    Model:                            OLS   Adj. R-squared:                  0.665
    Method:                 Least Squares   F-statistic:                     34.28
    Date:                Thu, 22 Aug 2019   Prob (F-statistic):           3.48e-15
    Time:                        15:48:59   Log-Likelihood:                -205.92
    No. Observations:                  68   AIC:                             421.8
    Df Residuals:                      63   BIC:                             432.9
    Df Model:                           4                                         
    Covariance Type:            nonrobust                                         
    ===============================================================================
                      coef    std err          t      P>|t|      [0.025      0.975]
    -------------------------------------------------------------------------------
    Intercept   -8484.7720   4664.146     -1.819      0.074   -1.78e+04     835.780
    C(lg)[T.NL]    -2.2736      1.325     -1.716      0.091      -4.922       0.375
    ln_h           -1.3542      0.875     -1.547      0.127      -3.103       0.395
    year            4.2277      2.324      1.819      0.074      -0.417       8.872
    g               0.1841      0.029      6.258      0.000       0.125       0.243
    ==============================================================================
    Omnibus:                       10.875   Durbin-Watson:                   1.999
    Prob(Omnibus):                  0.004   Jarque-Bera (JB):               17.298
    Skew:                           0.537   Prob(JB):                     0.000175
    Kurtosis:                       5.225   Cond. No.                     1.49e+07
    ==============================================================================
    
    Warnings:
    [1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
    [2] The condition number is large, 1.49e+07. This might indicate that there are
    strong multicollinearity or other numerical problems.
    

    unix 的 pipe 与后来出现的 dplyrmagrittr 启发了pipe 方法,在此,引入了 R 语言里用于读取 pipe 的操作符 (%>%)。pipe 的实现思路非常清晰,仿佛 Python 源生的一样。强烈建议大家阅读 pipe() 的源代码。

    行列级函数应用

    apply() 方法可以沿着 DataFrame 的轴应用任何函数,比如,描述性统计方法,该方法支持 axis 参数。

    In [141]: df.apply(np.mean)
    Out[141]: 
    one      0.811094
    two      1.360588
    three    0.187958
    dtype: float64
    
    In [142]: df.apply(np.mean, axis=1)
    Out[142]: 
    a    1.583749
    b    0.734929
    c    1.133683
    d   -0.166914
    dtype: float64
    
    In [143]: df.apply(lambda x: x.max() - x.min())
    Out[143]: 
    one      1.051928
    two      1.632779
    three    1.840607
    dtype: float64
    
    In [144]: df.apply(np.cumsum)
    Out[144]: 
            one       two     three
    a  1.394981  1.772517       NaN
    b  1.738035  3.684640 -0.050390
    c  2.433281  5.163008  1.177045
    d       NaN  5.442353  0.563873
    
    In [145]: df.apply(np.exp)
    Out[145]: 
            one       two     three
    a  4.034899  5.885648       NaN
    b  1.409244  6.767440  0.950858
    c  2.004201  4.385785  3.412466
    d       NaN  1.322262  0.541630
    

    apply() 方法还支持通过函数名字符串调用函数。

    In [146]: df.apply('mean')
    Out[146]: 
    one      0.811094
    two      1.360588
    three    0.187958
    dtype: float64
    
    In [147]: df.apply('mean', axis=1)
    Out[147]: 
    a    1.583749
    b    0.734929
    c    1.133683
    d   -0.166914
    dtype: float64
    

    默认情况下,apply() 调用的函数返回的类型会影响 DataFrame.apply 输出结果的类型。

    • 函数返回的是 Series 时,最终输出的结果是 DataFrame。输出的列与函数返回的 Series 索引相匹配。

    • 函数返回其它任意类型时,输出结果是 Series

    result_type 会覆盖默认行为,该参数有三个选项:reducebroadcastexpand。这些选项决定了列表型返回值是否扩展为 DataFrame

    用好 apply() 可以了解数据集的很多信息。比如可以提取每列的最大值对应的日期:

    In [148]: tsdf = pd.DataFrame(np.random.randn(1000, 3), columns=['A', 'B', 'C'],
       .....:                     index=pd.date_range('1/1/2000', periods=1000))
       .....: 
    
    In [149]: tsdf.apply(lambda x: x.idxmax())
    Out[149]: 
    A   2000-08-06
    B   2001-01-18
    C   2001-07-18
    dtype: datetime64[ns]
    

    还可以向 apply() 方法传递额外的参数与关键字参数。比如下例中要应用的这个函数:

    def subtract_and_divide(x, sub, divide=1):
        return (x - sub) / divide
    

    可以用下列方式应用该函数:

    df.apply(subtract_and_divide, args=(5,), divide=3)
    

    为每行或每列执行 Series 方法的功能也很实用:

    In [150]: tsdf
    Out[150]: 
                       A         B         C
    2000-01-01 -0.158131 -0.232466  0.321604
    2000-01-02 -1.810340 -3.105758  0.433834
    2000-01-03 -1.209847 -1.156793 -0.136794
    2000-01-04       NaN       NaN       NaN
    2000-01-05       NaN       NaN       NaN
    2000-01-06       NaN       NaN       NaN
    2000-01-07       NaN       NaN       NaN
    2000-01-08 -0.653602  0.178875  1.008298
    2000-01-09  1.007996  0.462824  0.254472
    2000-01-10  0.307473  0.600337  1.643950
    
    In [151]: tsdf.apply(pd.Series.interpolate)
    Out[151]: 
                       A         B         C
    2000-01-01 -0.158131 -0.232466  0.321604
    2000-01-02 -1.810340 -3.105758  0.433834
    2000-01-03 -1.209847 -1.156793 -0.136794
    2000-01-04 -1.098598 -0.889659  0.092225
    2000-01-05 -0.987349 -0.622526  0.321243
    2000-01-06 -0.876100 -0.355392  0.550262
    2000-01-07 -0.764851 -0.088259  0.779280
    2000-01-08 -0.653602  0.178875  1.008298
    2000-01-09  1.007996  0.462824  0.254472
    2000-01-10  0.307473  0.600337  1.643950
    

    apply() 有一个参数 raw,默认值为 False,在应用函数前,使用该参数可以将每行或列转换为 Series。该参数为 True 时,传递的函数接收 ndarray 对象,若不需要索引功能,这种操作能显著提高性能。

    聚合 API

    0.20.0 版新增

    聚合 API 可以快速、简洁地执行多个聚合操作。Pandas 对象支持多个类似的 API,如 groupby APIwindow functions APIresample API。聚合函数为DataFrame.aggregate(),它的别名是 DataFrame.agg()

    这里使用与前例类似的 DataFrame

    In [152]: tsdf = pd.DataFrame(np.random.randn(10, 3), columns=['A', 'B', 'C'],
       .....:                     index=pd.date_range('1/1/2000', periods=10))
       .....: 
    
    In [153]: tsdf.iloc[3:7] = np.nan
    
    In [154]: tsdf
    Out[154]: 
                       A         B         C
    2000-01-01  1.257606  1.004194  0.167574
    2000-01-02 -0.749892  0.288112 -0.757304
    2000-01-03 -0.207550 -0.298599  0.116018
    2000-01-04       NaN       NaN       NaN
    2000-01-05       NaN       NaN       NaN
    2000-01-06       NaN       NaN       NaN
    2000-01-07       NaN       NaN       NaN
    2000-01-08  0.814347 -0.257623  0.869226
    2000-01-09 -0.250663 -1.206601  0.896839
    2000-01-10  2.169758 -1.333363  0.283157
    

    应用单个函数时,该操作与 apply() 等效,这里也可以用字符串表示聚合函数名。下面的聚合函数输出的结果为 Series

    In [155]: tsdf.agg(np.sum)
    Out[155]: 
    A    3.033606
    B   -1.803879
    C    1.575510
    dtype: float64
    
    In [156]: tsdf.agg('sum')
    Out[156]: 
    A    3.033606
    B   -1.803879
    C    1.575510
    dtype: float64
    
    # 因为应用的是单个函数,该操作与`.sum()` 是等效的
    In [157]: tsdf.sum()
    Out[157]: 
    A    3.033606
    B   -1.803879
    C    1.575510
    dtype: float64
    

    Series 进行单个聚合操作,返回的是标量值:

    In [158]: tsdf.A.agg('sum')
    Out[158]: 3.033606102414146
    

    多函数聚合

    还可以用列表形式传递多个聚合函数。每个函数在输出结果 DataFrame 里以行的形式显示,行名是每个聚合函数的函数名。

    In [159]: tsdf.agg(['sum'])
    Out[159]: 
                A         B        C
    sum  3.033606 -1.803879  1.57551
    

    多个函数输出多行:

    In [160]: tsdf.agg(['sum', 'mean'])
    Out[160]: 
                 A         B         C
    sum   3.033606 -1.803879  1.575510
    mean  0.505601 -0.300647  0.262585
    

    对于 Series,多个函数返回的结果也是 Series,其索引为函数名:

    In [161]: tsdf.A.agg(['sum', 'mean'])
    Out[161]: 
    sum     3.033606
    mean    0.505601
    Name: A, dtype: float64
    

    传递 lambda 函数时,输出名为 <lambda> 的行:

    In [162]: tsdf.A.agg(['sum', lambda x: x.mean()])
    Out[162]: 
    sum         3.033606
    <lambda>    0.505601
    Name: A, dtype: float64
    

    应用自定义函数时,则该函数名为输出结果的行名:

    In [163]: def mymean(x):
       .....:     return x.mean()
       .....: 
    
    In [164]: tsdf.A.agg(['sum', mymean])
    Out[164]: 
    sum       3.033606
    mymean    0.505601
    Name: A, dtype: float64
    

    用字典实现聚合

    指定为哪些列应用哪些聚合函数时,需要把包含列名与标量(或标量列表)的字典传递给 DataFrame.agg

    注意:这里输出结果的顺序不是固定的,要想让输出顺序与输入顺序一致,请使用 OrderedDict

    In [165]: tsdf.agg({'A': 'mean', 'B': 'sum'})
    Out[165]: 
    A    0.505601
    B   -1.803879
    dtype: float64
    

    输入的参数是列表时,输出结果为 DataFrame,并以矩阵形式显示所有聚合函数的计算结果,且输出结果由所有唯一函数组成。未执行聚合操作的列输出结果为 NaN 值:

    In [166]: tsdf.agg({'A': ['mean', 'min'], 'B': 'sum'})
    Out[166]: 
                 A         B
    mean  0.505601       NaN
    min  -0.749892       NaN
    sum        NaN -1.803879
    

    多种 Dtype

    DataFrame 里包含不能执行聚合操作的多种 Dtype 时,.agg 只计算可以执行聚合的列。这与 groupby.agg 操作类似:

    In [167]: mdf = pd.DataFrame({'A': [1, 2, 3],
       .....:                     'B': [1., 2., 3.],
       .....:                     'C': ['foo', 'bar', 'baz'],
       .....:                     'D': pd.date_range('20130101', periods=3)})
       .....: 
    
    In [168]: mdf.dtypes
    Out[168]: 
    A             int64
    B           float64
    C            object
    D    datetime64[ns]
    dtype: object
    
    In [169]: mdf.agg(['min', 'sum'])
    Out[169]: 
         A    B          C          D
    min  1  1.0        bar 2013-01-01
    sum  6  6.0  foobarbaz        NaT
    

    自定义 Describe

    .agg() 可以轻松地创建与内置 describe 函数类似的自定义 describe 函数。

    In [170]: from functools import partial
    
    In [171]: q_25 = partial(pd.Series.quantile, q=0.25)
    
    In [172]: q_25.__name__ = '25%'
    
    In [173]: q_75 = partial(pd.Series.quantile, q=0.75)
    
    In [174]: q_75.__name__ = '75%'
    
    In [175]: tsdf.agg(['count', 'mean', 'std', 'min', q_25, 'median', q_75, 'max'])
    Out[175]: 
                   A         B         C
    count   6.000000  6.000000  6.000000
    mean    0.505601 -0.300647  0.262585
    std     1.103362  0.887508  0.606860
    min    -0.749892 -1.333363 -0.757304
    25%    -0.239885 -0.979600  0.128907
    median  0.303398 -0.278111  0.225365
    75%     1.146791  0.151678  0.722709
    max     2.169758  1.004194  0.896839
    

    Transform API

    0.20.0 版新增

    transform() 方法返回的结果与原始数据具有同样索引,且大小相同。这个 API 支持同时处理多种操作,不用一个一个操作,且该 API 与 .agg API 类似。

    下面先创建一个 DataFrame:

    In [176]: tsdf = pd.DataFrame(np.random.randn(10, 3), columns=['A', 'B', 'C'],
       .....:                     index=pd.date_range('1/1/2000', periods=10))
       .....: 
    
    In [177]: tsdf.iloc[3:7] = np.nan
    
    In [178]: tsdf
    Out[178]: 
                       A         B         C
    2000-01-01 -0.428759 -0.864890 -0.675341
    2000-01-02 -0.168731  1.338144 -1.279321
    2000-01-03 -1.621034  0.438107  0.903794
    2000-01-04       NaN       NaN       NaN
    2000-01-05       NaN       NaN       NaN
    2000-01-06       NaN       NaN       NaN
    2000-01-07       NaN       NaN       NaN
    2000-01-08  0.254374 -1.240447 -0.201052
    2000-01-09 -0.157795  0.791197 -1.144209
    2000-01-10 -0.030876  0.371900  0.061932
    

    这里转换的是整个 DataFrame。.transform() 支持 Numpy 函数、字符串函数及自定义函数。

    In [179]: tsdf.transform(np.abs)
    Out[179]: 
                       A         B         C
    2000-01-01  0.428759  0.864890  0.675341
    2000-01-02  0.168731  1.338144  1.279321
    2000-01-03  1.621034  0.438107  0.903794
    2000-01-04       NaN       NaN       NaN
    2000-01-05       NaN       NaN       NaN
    2000-01-06       NaN       NaN       NaN
    2000-01-07       NaN       NaN       NaN
    2000-01-08  0.254374  1.240447  0.201052
    2000-01-09  0.157795  0.791197  1.144209
    2000-01-10  0.030876  0.371900  0.061932
    
    In [180]: tsdf.transform('abs')
    Out[180]: 
                       A         B         C
    2000-01-01  0.428759  0.864890  0.675341
    2000-01-02  0.168731  1.338144  1.279321
    2000-01-03  1.621034  0.438107  0.903794
    2000-01-04       NaN       NaN       NaN
    2000-01-05       NaN       NaN       NaN
    2000-01-06       NaN       NaN       NaN
    2000-01-07       NaN       NaN       NaN
    2000-01-08  0.254374  1.240447  0.201052
    2000-01-09  0.157795  0.791197  1.144209
    2000-01-10  0.030876  0.371900  0.061932
    
    In [181]: tsdf.transform(lambda x: x.abs())
    Out[181]: 
                       A         B         C
    2000-01-01  0.428759  0.864890  0.675341
    2000-01-02  0.168731  1.338144  1.279321
    2000-01-03  1.621034  0.438107  0.903794
    2000-01-04       NaN       NaN       NaN
    2000-01-05       NaN       NaN       NaN
    2000-01-06       NaN       NaN       NaN
    2000-01-07       NaN       NaN       NaN
    2000-01-08  0.254374  1.240447  0.201052
    2000-01-09  0.157795  0.791197  1.144209
    2000-01-10  0.030876  0.371900  0.061932
    

    这里的 transform() 接受单个函数;与 ufunc 等效。

    In [182]: np.abs(tsdf)
    Out[182]: 
                       A         B         C
    2000-01-01  0.428759  0.864890  0.675341
    2000-01-02  0.168731  1.338144  1.279321
    2000-01-03  1.621034  0.438107  0.903794
    2000-01-04       NaN       NaN       NaN
    2000-01-05       NaN       NaN       NaN
    2000-01-06       NaN       NaN       NaN
    2000-01-07       NaN       NaN       NaN
    2000-01-08  0.254374  1.240447  0.201052
    2000-01-09  0.157795  0.791197  1.144209
    2000-01-10  0.030876  0.371900  0.061932
    

    .transform()Series 传递单个函数时,返回的结果也是单个 Series

    In [183]: tsdf.A.transform(np.abs)
    Out[183]: 
    2000-01-01    0.428759
    2000-01-02    0.168731
    2000-01-03    1.621034
    2000-01-04         NaN
    2000-01-05         NaN
    2000-01-06         NaN
    2000-01-07         NaN
    2000-01-08    0.254374
    2000-01-09    0.157795
    2000-01-10    0.030876
    Freq: D, Name: A, dtype: float64
    

    多函数 Transform

    transform() 调用多个函数时,将生成多重索引 DataFrame。第一层是原始数据集的列名;第二层是 transform() 调用的函数名。

    In [184]: tsdf.transform([np.abs, lambda x: x + 1])
    Out[184]: 
                       A                   B                   C          
                absolute  <lambda>  absolute  <lambda>  absolute  <lambda>
    2000-01-01  0.428759  0.571241  0.864890  0.135110  0.675341  0.324659
    2000-01-02  0.168731  0.831269  1.338144  2.338144  1.279321 -0.279321
    2000-01-03  1.621034 -0.621034  0.438107  1.438107  0.903794  1.903794
    2000-01-04       NaN       NaN       NaN       NaN       NaN       NaN
    2000-01-05       NaN       NaN       NaN       NaN       NaN       NaN
    2000-01-06       NaN       NaN       NaN       NaN       NaN       NaN
    2000-01-07       NaN       NaN       NaN       NaN       NaN       NaN
    2000-01-08  0.254374  1.254374  1.240447 -0.240447  0.201052  0.798948
    2000-01-09  0.157795  0.842205  0.791197  1.791197  1.144209 -0.144209
    2000-01-10  0.030876  0.969124  0.371900  1.371900  0.061932  1.061932
    

    为 Series 应用多个函数时,输出结果是 DataFrame,列名是 transform() 调用的函数名。

    In [185]: tsdf.A.transform([np.abs, lambda x: x + 1])
    Out[185]: 
                absolute  <lambda>
    2000-01-01  0.428759  0.571241
    2000-01-02  0.168731  0.831269
    2000-01-03  1.621034 -0.621034
    2000-01-04       NaN       NaN
    2000-01-05       NaN       NaN
    2000-01-06       NaN       NaN
    2000-01-07       NaN       NaN
    2000-01-08  0.254374  1.254374
    2000-01-09  0.157795  0.842205
    2000-01-10  0.030876  0.969124
    

    用字典执行 transform 操作

    函数字典可以为每列执行指定 transform() 操作。

    In [186]: tsdf.transform({'A': np.abs, 'B': lambda x: x + 1})
    Out[186]: 
                       A         B
    2000-01-01  0.428759  0.135110
    2000-01-02  0.168731  2.338144
    2000-01-03  1.621034  1.438107
    2000-01-04       NaN       NaN
    2000-01-05       NaN       NaN
    2000-01-06       NaN       NaN
    2000-01-07       NaN       NaN
    2000-01-08  0.254374 -0.240447
    2000-01-09  0.157795  1.791197
    2000-01-10  0.030876  1.371900
    

    transform() 的参数是列表字典时,生成的是以 transform() 调用的函数为名的多重索引 DataFrame。

    In [187]: tsdf.transform({'A': np.abs, 'B': [lambda x: x + 1, 'sqrt']})
    Out[187]: 
                       A         B          
                absolute  <lambda>      sqrt
    2000-01-01  0.428759  0.135110       NaN
    2000-01-02  0.168731  2.338144  1.156782
    2000-01-03  1.621034  1.438107  0.661897
    2000-01-04       NaN       NaN       NaN
    2000-01-05       NaN       NaN       NaN
    2000-01-06       NaN       NaN       NaN
    2000-01-07       NaN       NaN       NaN
    2000-01-08  0.254374 -0.240447       NaN
    2000-01-09  0.157795  1.791197  0.889493
    2000-01-10  0.030876  1.371900  0.609836
    

    元素级函数应用

    并非所有函数都能矢量化,即接受 Numpy 数组,返回另一个数组或值,DataFrame 的 applymap() 及 Series 的 map() ,支持任何接收单个值并返回单个值的 Python 函数。

    示例如下:

    In [188]: df4
    Out[188]: 
            one       two     three
    a  1.394981  1.772517       NaN
    b  0.343054  1.912123 -0.050390
    c  0.695246  1.478369  1.227435
    d       NaN  0.279344 -0.613172
    
    In [189]: def f(x):
       .....:     return len(str(x))
       .....: 
    
    In [190]: df4['one'].map(f)
    Out[190]: 
    a    18
    b    19
    c    18
    d     3
    Name: one, dtype: int64
    
    In [191]: df4.applymap(f)
    Out[191]: 
       one  two  three
    a   18   17      3
    b   19   18     20
    c   18   18     16
    d    3   19     19
    

    Series.map() 还有个功能,可以“连接”或“映射”第二个 Series 定义的值。这与 merging/joining 功能联系非常紧密:

    In [192]: s = pd.Series(['six', 'seven', 'six', 'seven', 'six'],
       .....:               index=['a', 'b', 'c', 'd', 'e'])
       .....: 
    
    In [193]: t = pd.Series({'six': 6., 'seven': 7.})
    
    In [194]: s
    Out[194]: 
    a      six
    b    seven
    c      six
    d    seven
    e      six
    dtype: object
    
    In [195]: s.map(t)
    Out[195]: 
    a    6.0
    b    7.0
    c    6.0
    d    7.0
    e    6.0
    dtype: float64
    

    Pandas 中文官档 ~ 基础用法1
    Pandas 中文官档 ~ 基础用法2
    Pandas 中文官档 ~ 基础用法3
    Pandas 中文官档 ~ 基础用法4
    Pandas 中文官档 ~ 基础用法5

    相关文章

      网友评论

        本文标题:Pandas中文官档~基础用法3

        本文链接:https://www.haomeiwen.com/subject/peysmctx.html