这是我拥有的数据集
id start end
0 A 1-Jan-19 31-Dec-19
1 A 1-Jan-20 31-Dec-20
2 B 13-Jun-19 19-Nov-19
df = pd.DataFrame({'id': ["A", "A", "B"],
'start': ["1-Jan-19", "1-Jan-20", "13-Jun-19"],
'end': ["31-Dec-19", "31-Dec-20", "19-Nov-19"]})
这是我需要的数据集
id start end
0 A 1-Jan-19 31-Jan-19
1 A 1-Feb-19 28-Feb-19
2 A 1-Mar-19 31-Mar-19
3 A 1-Apr-19 30-Apr-19
4 A 1-May-19 31-May-19
5 A 1-Jun-19 30-Jun-19
6 A 1-Jul-19 31-Jul-19
7 A 1-Aug-19 31-Aug-19
8 A 1-Sep-19 30-Sep-19
9 A 1-Oct-19 31-Oct-19
10 A 1-Nov-19 30-Nov-19
11 A 1-Dec-19 31-Dec-19
12 B 13-Jun-19 30-Jun-19
13 B 1-Jul-19 31-Jul-19
14 B 1-Aug-19 31-Aug-19
15 B 1-Sep-19 30-Sep-19
16 B 1-Oct-19 31-Oct-19
17 B 1-Nov-19 19-Nov-19
数据按ID分组,时间块分布在几个月内。我尝试使用重新采样和填充熊猫方法没有成功。是否可以使用Pandas做到这一点,或者我需要通过对日期系列进行合并并过滤日期重叠的地方来解决该方法?
谢谢
答案 0 :(得分:0)
这是解决方案。
from dateutil.relativedelta import relativedelta
import pandas as pd
import numpy as np
df1 = pd.DataFrame({'id': ["A", "A", "B"],
'start': ["1-Jan-19", "1-Jan-20", "13-Jun-19"],
'end': ["31-Dec-19", "31-Dec-20", "19-Nov-19"]})
df1["start"] = df1["start"].apply(lambda x: datetime.strptime(x, "%d-%b-%y") )
df1["end"] = df1["end"].apply(lambda x: datetime.strptime(x, "%d-%b-%y") )
df1["rows"] = abs((df1["start"]-df1["end"])/np.timedelta64(1,'M')).astype(int)
df_new = pd.DataFrame([df1.ix[idx]
for idx in df1.index
for i in range(df1.ix[idx]['rows'] +1)])
df_new = df_new.reset_index(drop=True)
groups = df_new.groupby(["start", "end"],as_index = False)
grouped_df = groups.apply(lambda x: x.reset_index(drop = True)).reset_index().drop('level_0',axis = 1)
grouped_df["start"] =grouped_df.apply(lambda row : row["start"]+ relativedelta(months=row["level_1"]), axis =1)
grouped_df.drop(['level_1', 'rows'], axis =1 ,inplace = True)
grouped_df
我假设您跳过了第二个输入行的处理。
如果不是这种情况,请告诉我。
输入:
输出:
答案 1 :(得分:0)
我认为我的解决方案不是优雅的解决方案。但是,它将返回所需的输出。第一步,我只是导入包并像您一样制作df
数据框。
import pandas as pd
import datetime
from dateutil.rrule import rrule, MONTHLY
df = pd.DataFrame(
{
'id': ["A", "A", "B"],
'start': ["1-Jan-19", "1-Jan-20", "13-Jun-19"],
'end': ["31-Dec-19", "31-Dec-20", "19-Nov-19"]
}
)
在第二部分中,我遍历df
数据帧中的每一行,并尝试为第二个数据帧创建一个项-我将其称为df_2
。项目存储在data_items
列表中。
data_items = []
for id_, start, end in zip(df['id'], df['start'], df['end']):
start_dt = datetime.datetime.strptime(start, '%d-%b-%y')
end_dt = datetime.datetime.strptime(end, '%d-%b-%y')
start_dates = [dt for dt in rrule(MONTHLY, dtstart=start_dt, until=end_dt.replace(day=start_dt.day))]
for i, start_date in enumerate(start_dates):
if i == len(start_dates) - 1:
end_date = end_dt
elif start_date.month == 12:
end_date = start_date.replace(day=31)
else:
end_date = start_date.replace(month=start_date.month + 1, day=1) - datetime.timedelta(days=1)
data_items.append(
{
'id': id_,
'start': start_date if i == 0 else start_date.replace(day=1),
'end': end_date
}
)
您可以检查df_2
中的输出是否要实现。
df_2 = pd.DataFrame(data_items)
df_2[['id', 'start', 'end']]
答案 2 :(得分:0)
从定义要应用于每一行的函数开始:
def expDates(row):
d1 = pd.to_datetime(row.start)
d2 = pd.to_datetime(row.end)
stList = [d.strftime('%#d-%b-%y') for d in pd.date_range(d1, d2, freq='MS')]
if len(stList) == 0:
stList.append(row.start)
elif stList[0] != row.start:
stList.insert(0, row.start)
endList = [d.strftime('%#d-%b-%y') for d in pd.date_range(d1, d2, freq='M')]
if len(endList) == 0 or endList[-1] != row.end:
endList.append(row.end)
return pd.DataFrame({'id': row.id, 'start': stList, 'end': endList})
然后应用此功能,将结果保存为DataFrames列表:
tbl = df.apply(expDates, axis=1).tolist()
最后一步是连接这些DataFrame:
pd.concat(tbl, ignore_index=True)
在我看来,此解决方案不太“ pythonic”,而更“ pandasonic” 然后所有其他人。