繁体   English   中英

使用Pandas以更有效的方式在后续行之间应用函数

[英]Apply function between subsequent rows in more efficient way with Pandas

我有一个数据帧df定义如下:

import numpy as np
import pandas as pd
dic = {'A':['1A','1A','3C','3C','3C','7M','7M','7M'],'B':[10,15,49,75,35,33,45,65],'C':[11,56,32,78,45,89,15,14],'D':[111,0,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan],'E':[0,222,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan]}

df = pd.DataFrame(dic)

我的目标是在A列中具有相同项目的行之间执行一些计算。

该函数定义如下(但可以是任何东西):

def fun(a,b,c,d):
    out = a*c + b/2 + d*b
    return out

此类操作的结果将根据以下规则存储在D列和E列中:

# Fill column D
for j in range(0,len(df)-1):
    if df['A'].iloc[j]==df['A'].iloc[j+1] and pd.isnull(df['D'].iloc[j]):
        df['D'].iloc[j] = fun(df['B'].iloc[j],df['B'].iloc[j],df['B'].iloc[j+1],df['B'].iloc[j+1])  

# Fill column E       
for j in reversed(range(1,len(df))):
    if df['A'].iloc[j-1]==df['A'].iloc[j] and pd.isnull(df['E'].iloc[j]):
        df['E'].iloc[j] = fun(df['B'].iloc[j],df['B'].iloc[j],df['B'].iloc[j-1],df['B'].iloc[j-1])   

两个循环非常相似,但第二个循环从最后一个元素循环到数据帧的第一个元素。 我的代码工作正常,结果应该是这样的:

          # Before #                         # After #
    A   B   C    D    E          A   B   C       D       E
0  1A  10  11  111    0      0  1A  10  11   111.0     0.0
1  1A  15  56    0  222      1  1A  15  56     0.0   222.0
2  3C  49  32  NaN  NaN      2  3C  49  32  7374.5     NaN
3  3C  75  78  NaN  NaN      3  3C  75  78  5287.5  7387.5
4  3C  35  45  NaN  NaN      4  3C  35  45     NaN  5267.5
5  7M  33  89  NaN  NaN      5  7M  33  89  2986.5     NaN
6  7M  45  15  NaN  NaN      6  7M  45  15  5872.5  2992.5
7  7M  65  14  NaN  NaN      7  7M  65  14     NaN  5882.5

您是否能够使用Pandas库中的一些内置函数来改进此类代码以使其更高效? 我希望有一些更优雅的方式来实现我的结果。

注意 :第一行和第二行已经有一个值( 111 00 222 ),因此它们不能由函数计算!

你可以使用np.wheredataframe.shift ()

  • np.where就像一个if语句
  • datafrmae.shift() - 使用可选的时间频率按期望的周期数移动索引

      df['D']=np.where(df.A.shift(-1)==df.A,func(df['B'],df['B'],df.B.shift(-1),df.B.shift(-1)),np.NaN) 

您可以先按A的值进行分组,然后应用矢量化函数:

def fun(a,b,c,d):
    out = a*c + b/2 + d*b
    return out

def apply_func(df):
    mask = pd.isnull(df['D'][:-1])
    df['D'][:-1][mask] = fun(df['B'][:-1].values, df['B'][:-1].values, 
                             df['B'][1:].values, df['B'][1:].values)
    mask = pd.isnull(df['E'][1:])
    df['E'][1:][mask] = fun(df['B'][1:].values, df['B'][1:].values, 
                            df['B'][:-1].values, df['B'][:-1].values)
    return df

然后 :

df = df.groupby('A').apply(apply_func).reset_index(drop=True)

    A   B   C       D       E
0  1A  10  11   305.0     NaN
1  1A  15  56     NaN   307.5
2  3C  49  32  7374.5     NaN
3  3C  75  78  5287.5  7387.5
4  3C  35  45     NaN  5267.5
5  7M  33  89  2986.5     NaN
6  7M  45  15  5872.5  2992.5
7  7M  65  14     NaN  5882.5

为了解决我的问题,我定义了另一个带有输入fun

def fun2(df,s):
    X= fun(df.B,df.C,df.B.shift(s),df.C.shift(s))
    return X

DE可以像这样填充:

df2['D']=np.where((df2.A.shift(-1)==df2.A) & (df2.D.isnull()==True),fun2(df2,-1),df2.D) 
df2['E']=np.where((df2.A.shift(1)==df2.A) & (df2.E.shift(1).isnull()==True),fun2(df2,+1),df2.E)

注意 :即使更紧凑,这种方法可能会更慢

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM