clg*_*lg4 3 python lambda dataframe pandas
我有以下测试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))
Run Code Online (Sandbox Code Playgroud)
它给出了如下所示的数据框,公司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
Run Code Online (Sandbox Code Playgroud)
我需要做的是:计算cid发生的jid数,对于min(stdt)和max(enddt)之间的每个日期(newdate),其中newdate在stdt和enddt之间.
结果数据集应该是每个cid具有的数据帧,特定于每个cid的min(stdt)和max(enddt)之间的列日期范围(newdate),以及该数字的count(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
Run Code Online (Sandbox Code Playgroud)
我相信应该有一种方法可以使用pandas groupby(groupby cid)和某种形式的lambda(?)来pythonically创建这个新的数据帧.
我目前为每个cid运行一个循环(我将cid行切换到主df之外),在循环中确定相关的日期范围(每个cid帧的最小stdt和max enddt,然后是每个新的日期(范围记录) -maxdate)它计算newdate在每个jid的stdt和enddt之间的jid数.然后我将每个结果数据集附加到一个新的数据框中,如上所示.
但从资源和时间的角度来看,这是非常昂贵的.对数以千计的cid进行数以百计的jid这样做需要一整天.我希望这里有一个简单的(r)熊猫解决方案.
我对这些问题的常用方法是根据事件改变累加器进行调整和思考.我们看到的每个新"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
Run Code Online (Sandbox Code Playgroud)
那么我们想要的只是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)
Run Code Online (Sandbox Code Playgroud)
这给了我类似的东西
>>> 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
Run Code Online (Sandbox Code Playgroud)
关于您的期望可能存在一个一个一个的差异; 你可能对如何jid在同一时间窗口中处理多个重叠s 有不同的想法(这里它们会算作2); 但即使你必须调整细节,使用事件的基本思想也应该有用.
| 归档时间: |
|
| 查看次数: |
2360 次 |
| 最近记录: |