【问题标题】:Optimizing pandas iteration优化 pandas 迭代
【发布时间】:2020-07-14 22:55:51
【问题描述】:
Customer  Year   Customer Lost/Retained
A         2009          Retained
A         2010          Retained   
A         2011          Lost
B         2008          Lost
C         2008          Retained
C         2009          lost

我已经使用 itterrows() 根据上述逻辑创建客户丢失/保留列。

如果客户连续一年重复,他会被保留,否则会丢失。

for i, row in df.iterrows(): 
    if (df[df['Year'] == row['Year']+1]['Customer']).str.contains(df['Customer'].iloc[i]).any():
        df['Customer Lost/Retained'].iloc[i] = 'Retained'
    else:
        df['Customer Lost/Retained'].iloc[i] = 'Lost'

这段代码可以进一步优化吗?

【问题讨论】:

    标签: python-3.x pandas optimization iteration


    【解决方案1】:
    # groupby customer
    g = df.groupby('Customer')['Year']
    # create a mask of conditions by using shift
    mask = (g.shift(0) == g.shift(-1)-1)
    # use npy.wehre to create a list of results based on the mask
    df['Retained/lost'] = np.where(mask, 'Retained', 'Lost')
    
      Customer  Year Retained/lost
    0        A  2009      Retained
    1        A  2010      Retained
    2        A  2011          Lost
    3        B  2008          Lost
    4        C  2008      Retained
    5        C  2009          Lost
    

    【讨论】:

    • 这个依赖于按年份排序,但在其他方面是一个不错的解决方案
    • @Randy 是的,确实如此。我忘了在解决方案中提到这一点。感谢您指出这一点。
    【解决方案2】:

    您可以将其作为 merge 来执行此操作,但要修改年份:

    In [83]: df['retained'] = pd.notnull(df.merge(
        ...:     df,
        ...:     how="left",
        ...:     left_on=["Customer", "Year"],
        ...:     right_on=["Customer", df["Year"].sub(1)],
        ...:     suffixes=['', "_match"]
        ...: )["Year_match"]).map({True: 'Retained', False: 'Lost'})
    
    In [84]: df
    Out[84]:
      Customer  Year Customer Lost/Retained  retained
    0        A  2009               Retained  Retained
    1        A  2010               Retained  Retained
    2        A  2011                   Lost      Lost
    3        B  2008                   Lost      Lost
    4        C  2008               Retained  Retained
    5        C  2009                   lost      Lost
    

    【讨论】:

    • 很好的解决方案。我总是喜欢看到人们解决同一个问题的不同方式。即使将 merge 作为选项 +1
    【解决方案3】:

    我们添加一列 'Retained':

    df['Customer Lost/Retained'] = 'Retained'
    

    除了每个客户年份最高的指数外,它们都获得价值'Lost'

    mask = df.groupby('Customer')['Year'].idxmax()
    df.loc[mask, 'Customer Lost/Retained'] = 'Lost'
    
      Customer  Year Customer Lost/Retained
    0        A  2009               Retained
    1        A  2010               Retained
    2        A  2011                   Lost
    3        B  2008                   Lost
    4        C  2008               Retained
    5        C  2009                   Lost
    

    或者,或者,先插入'Lost',然后插入.fillna()

    df.loc[df.groupby('Customer')['Year'].idxmax(), 'Customer Lost/Retained'] = 'Lost'
    df['Customer Lost/Retained'] = df['Customer Lost/Retained'].fillna('Retained')
    

    【讨论】:

    • 这仅适用于数据中没有年份间隔的情况。
    • 是的,这里的假设是客户不会丢失多次。
    • 符合OP的要求权利:“如果客户连续一年重复,则保留,否则丢失”。
    • 我对此的解释是,由于 2010 年的差距,拥有 2008 年、2009 年、2011 年和 2012 年的客户在 2009 年和 2012 年都将被视为丢失。
    • 这不起作用,因为如果客户在最大年份出现,它会将值设为“保留”。我的情况是,如果 2008 年的客户 A 在 2009 年出现,那么 2008 年的 A 将被保留。即使 A 在 2010 年或 2011 年在场,此代码也会保留 A。
    猜你喜欢
    • 1970-01-01
    • 2019-07-23
    • 2021-07-25
    • 2013-05-29
    • 1970-01-01
    • 1970-01-01
    • 2020-04-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多