Python 基于项目和ID的两列求和

Python 基于项目和ID的两列求和,python,pandas,numpy,Python,Pandas,Numpy,目前,我正在寻找基于ID和项目开始日期的每个项目类型(又名groupby)的单个ID的30天总和()。每次出现相同的ID和项目代码时,都应重复此操作。我知道这个查询可以帮助我通过ID和项目获得月度金额,但月度金额不能回答我的问题 以下是一个示例数据集: ID Project Amount Start Date 1234 203 29.65 5/29/18 1234 203 2 6/24/18 1234 203 345.34 7/12/18 1234

目前,我正在寻找基于ID和项目开始日期的每个项目类型(又名groupby)的单个ID的30天总和()。每次出现相同的ID和项目代码时,都应重复此操作。我知道这个查询可以帮助我通过ID和项目获得月度金额,但月度金额不能回答我的问题

以下是一个示例数据集:

ID  Project Amount  Start Date
1234    203 29.65   5/29/18
1234    203 2       6/24/18
1234    203 345.34  7/12/18
1234    201 100     7/16/18
1234    203 200     7/16/18
2345    251 3       4/11/17
2345    251 4       4/16/17
2345    203 95.12   8/13/18
2345    203 10      4/12/19
3456    251 50      3/23/18
3456    251 100     3/23/18
3456    251 43.75   6/5/18
在过去,我尝试了一个基本查询,该查询为我提供了groupby ID和Project,以及金额的每月总和()。然而,每月进行一次总结并不能回答我的问题。我想30天的时间框架开始时,ID和项目是第一次看到

下面是我用于每月合计的示例代码

df.groupby(['ID', 'Project', pd.Grouper(key='Date', freq='M')])['Amount'].sum()

理想的解决方案是使用:

import pandas as pd
import numpy as np

df = pd.read_csv('something.csv')

df['Start Date'] = pd.to_datetime(df['Start Date'], infer_datetime_format=True)
df = df.sort_values(by='Start Date')
new_df1 = (df.groupby(['ID', 'Project', pd.Grouper(key='Start Date', freq='M')]).agg({'Amount':'sum'}))
print(new_df1)
这给了你:

ID   Project Start Date        
1234 201     2018-07-31  100.00
     203     2017-04-30  200.00
             2018-05-31   29.65
             2018-06-30   52.00
             2018-07-31  645.34
2345 203     2018-08-31   95.12
             2019-04-30   10.00
     251     2017-04-30    7.00
3456 251     2018-03-31  150.00
             2018-06-30   43.75
但是,这与您的有点不同,因为您希望添加到6/12/18和6/24/18中的“5/29/18”值实际上不在同一个月内-因此它被视为独立值

如果您想根据“开始日期”列中的日期自定义频率,解决方案是根据日期排序,使用第一个日期作为开始日期并向其添加30,找到该范围内的所有值,并为其分配一些唯一的“期间”id(我将其设置为开始值的索引),然后找到超出范围的第一个值,并将其重新指定为start,然后重复该过程。这是一个工作代码,它可以生成您想要的输出:

import pandas as pd
import numpy as np

df = pd.read_csv('something.csv')

df['Start Date'] = pd.to_datetime(df['Start Date'], infer_datetime_format=True)
df = df.sort_values(by='Start Date')

df['Period'] = np.nan
indices = df.index.values.tolist()
start = indices[0]
for v in range(0, len(indices)):
    if v == 0:
        df['Period'] = start
    else:
        if df['Start Date'].loc[indices[v]] - df['Start Date'].loc[start] < pd.Timedelta(days=30):
            df['Period'].loc[indices[v]] = start
        else:
            df['Period'].loc[indices[v]] = indices[v] 
            start = indices[v]
new_df = (df.groupby(['ID', 'Project', 'Period']).agg({'Amount':'sum'}))
print(new_df)

与其让它为空,你能做一个连续的计数,让该列等于当前金额的值吗?@AnnaNevison这是一个很好的建议。不幸的是,我很难找到一个特定ID和项目的平均值。如果计数显示为空白,我知道它已经被添加到另一个项目中,因此我可以很容易地筛选数据。您是否愿意创建第五列,该列是真的还是假的,以便您能够排序它是否是您想要的平均值?空格将很难排序,因为它们将是none type vs.integer,而不是比较布尔true/False实际上,如果执行了一个运行求和或列等于当前数量,那么如果可以添加另一列,并添加某种我可以过滤的标志,那也行。你在读我的心思@AnnaNevison!如果创建了第五列,让我知道这是30天的最终总数,那么是的,那就太好了。我也在研究这个问题。很抱歉,如果我需要一些时间来运行代码。我只是想确保我不会浪费你更多的时间!我真的很感谢你花了这么多时间来帮助我。我知道你有自己的工作要做,所以我真的很珍惜你的时间!我会回顾一下,然后很快回复你。我想这就是问题变得复杂的地方。因此,我仍然期望有两个总数分别为31.65和545.34,标记为False。即使ID和项目是相同的,30天的窗口也应该针对两个不同的点。例如,2018年5月29日的开始日期应在2018年6月28日后30天结束。因此,2018年7月12日的345.34美元和2018年7月16日的200美元不应添加到之前的30天窗口中。应创建新的30天窗口总和。我说得通吗?最后一个问题是,如果可以的话,我是否应该关注以下警告信息:“/anaconda3/lib/python3.7/site packages/pandas/core/index.py:190:SettingWithCopyWarning:A值正试图在数据帧的切片副本上设置请参见文档中的警告:self.\u setitem\u with\u indexer(值索引器)还有,@Anna,非常感谢!!这正是我所期望的结果。我印象深刻,非常感谢。对于任何读到这篇文章的人,如果你的声望超过15分,请你投票支持Anna的回答好吗?不幸的是,我的分数不到15分,所以它没有显示出来。再次感谢你,Anna。像你和所有其他人一样的人谁在继续为让这里变得更好做出贡献!:)
import pandas as pd
import numpy as np

df = pd.read_csv('something.csv')

df['Start Date'] = pd.to_datetime(df['Start Date'], infer_datetime_format=True)
df = df.sort_values(by='Start Date')

df['Period'] = np.nan
indices = df.index.values.tolist()
start = indices[0]
for v in range(0, len(indices)):
    if v == 0:
        df['Period'] = start
    else:
        if df['Start Date'].loc[indices[v]] - df['Start Date'].loc[start] < pd.Timedelta(days=30):
            df['Period'].loc[indices[v]] = start
        else:
            df['Period'].loc[indices[v]] = indices[v] 
            start = indices[v]
new_df = (df.groupby(['ID', 'Project', 'Period']).agg({'Amount':'sum'}))
print(new_df)
ID   Project Period        
1234 201     6       100.00
     203     3        81.65
             6       645.34
             11      200.00
2345 203     9        95.12
             10       10.00
     251     11        7.00
3456 251     3        43.75
             13      150.00