当前位置: 首页 > 面试题库 >

通过pandas数据框按pandas ID中的两个日期之间的行数进行计数

易衡
2023-03-14
问题内容

我有以下测试DataFrame:

import random
from datetime import timedelta
import pandas as pd
import datetime

#create test range of dates
rng=pd.date_range(datetime.date(2015,1,1),datetime.date(2015,7,31))
rnglist=rng.tolist()
testpts = range(100,121)
#create test dataframe
d={'jid':[i for i in range(100,121)], 'cid':[random.randint(1,2) for _ in testpts],
    'stdt':[rnglist[random.randint(0,len(rng))] for _ in testpts]}
df=pd.DataFrame(d)
df['enddt'] = df['stdt']+timedelta(days=random.randint(2,32))

它给出了如下所示的数据框,其中包含公司ID列“ cid”,唯一ID列“ jid”,开始日期“ stdt”和enddt“ enddt”。

   cid  jid       stdt      enddt
0    1  100 2015-07-06 2015-07-13
1    1  101 2015-07-15 2015-07-22
2    2  102 2015-07-12 2015-07-19
3    2  103 2015-07-07 2015-07-14
4    2  104 2015-07-14 2015-07-21
5    1  105 2015-07-11 2015-07-18
6    1  106 2015-07-12 2015-07-19
7    2  107 2015-07-01 2015-07-08
8    2  108 2015-07-10 2015-07-17
9    2  109 2015-07-09 2015-07-16

我需要做的是:
计算min(stdt)和max(enddt)之间每个date(newdate)的cid发生的jid数目,其中newdate在stdt和enddt之间。

结果数据集应为每个cid具有一个数据帧,该数据帧的日期范围(新日期)在每个cid的min(stdt)和max(enddt)之间,并且该数字的计数(cnt)
jid表示newdate在min(stdt)和max(enddt)之间。得到的DataFrame应该看起来像(这仅是使用上述数据的1 cid):

cid newdate cnt
1   2015-07-06  1
1   2015-07-07  1
1   2015-07-08  1
1   2015-07-09  1
1   2015-07-10  1
1   2015-07-11  2
1   2015-07-12  3
1   2015-07-13  3
1   2015-07-14  2
1   2015-07-15  3
1   2015-07-16  3
1   2015-07-17  3
1   2015-07-18  3
1   2015-07-19  2
1   2015-07-20  1
1   2015-07-21  1
1   2015-07-22  1

我相信应该有一种方法可以使用pandas groupby(groupby cid)和某种形式的lambda(?)以Python方式创建此新数据框。

我目前正在运行一个循环,为每个cid(将cid行从主df中切出),在循环中确定相关的日期范围(每个cid帧的最小stdt和max
enddt,然后确定每个新日期(范围为minate) -maxdate),它计算jid的数目,其中newdate在每个jid的stdt和enddt之间。

但是,从资源和时间的角度来看,这是非常昂贵的。数以千计的jid花费了整整一天的时间。我希望这里有一个简单的熊猫解决方案。


问题答案:

对于这些问题,我通常的处理方法是围绕更改累加器的事件进行思考。我们看到的每个新的“ stdt”都会使计数增加+1;我们看到的每个“
enddt”都加-1。(第二天加-1,至少如果我解释您的方式“在两者之间”。某些时候,我认为我们应该禁止过于含糊地使用该词。)

IOW,如果我们将您的框架变成类似

>>> df.head()
    cid  jid  change       date
0     1  100       1 2015-01-06
1     1  101       1 2015-01-07
21    1  100      -1 2015-01-16
22    1  101      -1 2015-01-17
17    1  117       1 2015-03-01

那么我们想要的只是change(经过适当的重组后)的累积总和。例如,类似

df["enddt"] += timedelta(days=1)
df = pd.melt(df, id_vars=["cid", "jid"], var_name="change", value_name="date")
df["change"] = df["change"].replace({"stdt": 1, "enddt": -1})
df = df.sort(["cid", "date"])

df = df.groupby(["cid", "date"],as_index=False)["change"].sum()
df["count"] = df.groupby("cid")["change"].cumsum()

new_time = pd.date_range(df.date.min(), df.date.max())

df_parts = []
for cid, group in df.groupby("cid"):
    full_count = group[["date", "count"]].set_index("date")
    full_count = full_count.reindex(new_time)
    full_count = full_count.ffill().fillna(0)
    full_count["cid"] = cid
    df_parts.append(full_count)

df_new = pd.concat(df_parts)

这给了我类似的东西

>>> df_new.head(15)
            count  cid
2015-01-03      0    1
2015-01-04      0    1
2015-01-05      0    1
2015-01-06      1    1
2015-01-07      2    1
2015-01-08      2    1
2015-01-09      2    1
2015-01-10      2    1
2015-01-11      2    1
2015-01-12      2    1
2015-01-13      2    1
2015-01-14      2    1
2015-01-15      2    1
2015-01-16      1    1
2015-01-17      0    1

关于您的期望可能存在一对一的差异;您可能对如何jid在同一时间窗口中处理多个重叠的s有不同的想法(此处将它们计为2);但是即使必须微调细节,处理事件的基本思想也应被证明是有用的。



 类似资料:
  • 问题内容: 如果不使用PHP 5.3的date_diff函数(我使用的是PHP 5.2.17),是否有一种简单而准确的方法?我正在考虑以下代码,但是我不知道如何计算leap年: 我正在尝试计算一个人的月数。 问题答案: 您可能还希望将某天包括在内,具体取决于您是否指的是 整个 月。希望你能明白。

  • 我需要计算JPA中2个日期之间的天数。 例如: 到目前为止,我试着: 你会怎么做?

  • 问题内容: 我编写了以下代码来查找两个日期之间的日期 当开始日期和结束日期分别是2/3/2017和3/3/2017时,显示的天数是29.尽管它们是同一天,但显示的是1.(请假的天数。如果请假一天,他必须选择相同的开始日期和结束日期。因此,在这种情况下,他请了两天假。 我究竟做错了什么?感谢您的时间。 注意:请不要使用日期构造函数。检查下面接受的答案。使用simpledateformat或Joda时

  • 我写了以下代码来查找两个日期之间的日期 当开始日期和结束日期分别为2017年2月3日和2017年3月3日时,显示的天数为29天。虽然当他们在同一天,它是显示1。(一个人休假的天数。因此,如果一个人休假一天,他必须选择相同的开始和结束日期。因此,在这种情况下,他休假两天)。 我做错了什么?谢谢你抽出时间。 注意:请不要使用日期构造函数。检查下面被接受的答案。使用simpledateformat或Jo

  • 问题内容: 查看两个日期之间有多少整天的最短方法是什么?这就是我现在正在做的。 问题答案: 假设您确实有两个日期对象,则可以从另一个对象中减去一个,然后查询结果对象的天数: 它也适用于日期时间-我认为它会四舍五入到最近的日期:

  • 问题内容: 我有两个数据框 df1, df2, 我正在尝试在df1中获取包含df2中所有项目的行 我的预期输出是 我试过了, 但是我无法达到预期的输出,因为它具有(“,”)。请帮忙 问题答案: 使用集