【问题标题】:Pandas Create new column based on a count and a condition from another dataframePandas 根据来自另一个数据帧的计数和条件创建新列
【发布时间】:2021-03-22 01:35:23
【问题描述】:

问题

我有一个数据框 df 包含这样的产品:

ID  DATE        TYPE    Client_ID
1   2015-01-15  A       johndoe
2   2009-01-15  C       johndoe
3   2015-03-12  C       johndoe
4   2010-01-01  B       johndoe
5   2017-01-01  B       johndoe
6   2018-01-01  A       markdoe
7   2019-01-01  C       johndoe
8   2012-01-01  C       markdoe

从这个我创建了一个只有 A 类产品的数据框,df-A

ID  DATE        TYPE    Client_ID
1   2015-01-15  A       johndoe
6   2018-01-01  A       markdoe

我想要创建df-A 2 个变量,这些变量计算客户拥有的 B 型和 C 型产品的数量,其日期低于或等于分析的 A 产品。 我想要的结果:

ID  DATE        TYPE    Client_ID   NB-B    NB-C
1   2015-01-15  A       johndoe     1       1
6   2018-01-01  A       markdoe     0       1

第一行的NB-B 是1,因为johndoe 有2 个B 产品,但只有一个有Date <= 2015-01-15(这个产品是ID=4,日期为2010-01-01

我尝试了什么:

我是使用 iterrowsapply 完成的。这可能行得通,但需要很长时间,我真的需要通过一些 groupby 和聚合使其更快。

for index, row in df-A.iterrows():
    row['NB-B'] = df[(df['ID'] == row['ID']) & (df['DATE'] <= row['DATE'])].groupby('TYPE').count()['ID'].loc['B']

apply也一样

def B(x):
    return(row['NB-B'] = df[(df['ID'] == x['ID']) & (df['DATE'] <= x['DATE'])].groupby('TYPE').count()['ID'].loc['B'])

df-A.apply(lambda x: B(x), axis=1)

提前感谢您的帮助

编辑:@Quang Hoang 回答后的详细信息

一个客户可以在不同的日期拥有多个 A 类产品(我没有提到它是为了简化,因为问题已经很复杂,我没想到会做出很大的改变)。另外,我想像Bs和Cs一样统计客户购买新产品后拥有的A产品的数量。

例子:

ID  DATE        TYPE    Client_ID
1   2015-01-15  A       johndoe
2   2009-01-15  C       johndoe
3   2015-03-12  C       johndoe
4   2010-01-01  B       johndoe
5   2017-01-01  B       johndoe
6   2020-01-01  A       johndoe
7   2019-01-01  C       johndoe

预期结果:

ID  DATE        TYPE    Client_ID   NB-A   NB-B    NB-C
1   2015-01-15  A       johndoe     1      1       1
6   2018-01-01  A       johndoe     2      2       3

这个细节很重要,因为应用你的代码,我得到了以下错误:Reindexing only valid with uniquely valued Index objects 因为Client_ID,成为s 的新索引,不是唯一的。

我试图解决这个问题,但没有成功。

【问题讨论】:

    标签: python python-3.x pandas dataframe group-by


    【解决方案1】:

    让我们试试 pivot_table 并加入:

    # extract the A types
    aType = df.TYPE.eq('A')
    s = df[aType].set_index('Client_ID')
    
    (df[~aType].assign(valid=lambda x: x['DATE'].le(x['Client_ID'].map(s['DATE'])).astype(int))
       .pivot_table(index='Client_ID',columns='TYPE',
                    values='valid', aggfunc='max',
                    fill_value=0)
       .add_prefix('NB_')
       .join(s)
       .reset_index()
    )
    

    输出:

      Client_ID  NB_B  NB_C  ID        DATE TYPE
    0   johndoe     1     1   1  2015-01-15    A
    1   markdoe     0     1   6  2018-01-01    A
    

    【讨论】:

    • 非常感谢您的回答!但是,我仍然面临一个问题。我编辑了我的原始帖子以显示更多详细信息并解释我无法解决的问题。
    【解决方案2】:

    你可以试试

    Pandas.Series.str.count("string") 
    

    您提取要计为系列的列,然后应用serie.str.count("the string you are looking for")

    series = df["Client_ID"] 
      
    count = series.str.count("johndoe")
    

    您可以使用循环获取“Client_ID”系列中的所有名称

    这将计算“Client_ID”列中出现的所有“johndoe”

    【讨论】:

    • 这类似于我已经尝试过的解决方案。这可能有效,但它真的很长,因为你必须循环每个 df-A 行,并且每次从 df 中分离一个子数据帧然后进行计数
    猜你喜欢
    • 1970-01-01
    • 2019-07-10
    • 1970-01-01
    • 2020-09-20
    • 1970-01-01
    • 1970-01-01
    • 2019-03-19
    • 2017-11-10
    • 2013-06-14
    相关资源
    最近更新 更多