我有一个数据框df1,其日期为01的列,其值从01/09/2019到30/09/2019。即30个值和相应的计数。
DF1
date_1 count
01/09/2019 5
02/09/2019 4
03/09/2019 5
04/09/2019 6
05/09/2019 7
06/09/2019 8
07/09/2019 10
08/09/2019 9
09/09/2019 11
10/09/2019 12
11/09/2019 13
12/09/2019 14
13/09/2019 15
14/09/2019 16
我想生成一个数据帧df2,这样:
有一个新列date_2。
date_2是根据df1中存在的计数特征生成的。
例如:一个新的数据框df2在01/09/2019上有5个条目(因为计数= 5),date_2列的值可以是date_1之前30天到30/08/2019(date_1-1中的当前日期)
预期输出:
date_1 count date_2
01/09/2019 5 02/08/2019
01/09/2019 5 10/08/2019
01/09/2019 5 12/08/2019
01/09/2019 5 25/08/2019
01/09/2019 5 28/08/2019
02/09/2019 4 03/08/2019
02/09/2019 4 10/08/2019
02/09/2019 4 20/08/2019
02/09/2019 4 25/08/2019
可以从(30 - date_1
到date_1 - 1
的范围中随机选择date_2,即在我们的示例中,从01/08/2019到02/08/2019到30/08/2019
编辑
我能够使用以下函数生成随机的date_2:
def pick_random_delta_in_range(min_days=1, max_days=30):
if min_days is None and max_days is None:
return datetime.timedelta(days=1, minutes=0, seconds=0)
if min_days is None:
return max_days
if max_days is None:
return min_days
days_to_be_added = random.randint(min_days, max_days)
return datetime.timedelta(days=days_to_be_added, minutes=0, seconds=0)
def gen_date_by_delta(src_dates, date_format, delta_min, delta_max):
gen_dates = []
for dt in src_dates:
src_date = datetime.datetime.strptime(dt, date_format)
if src_date is None:
gen_dates.append("")
continue
chosen_delta = pick_random_delta_in_range(min_days=delta_min, max_days=delta_max)
result_date = (src_date + chosen_delta).strftime(date_format)
gen_dates.append(result_date)
return gen_dates
date_2 = gen_date_by_delta(src_dates=df1["date_1"], date_format=date_format, delta_min=1, delta_max=30)
我无法理解如何根据计数复制数据框中的字段并相应地生成日期。
*当前,增量是随机生成的,并且可能在同一date_1上生成相同的增量,从而导致条目重复。我不想生成重复的条目。 *
任何人都可以建议一种生成相同方法的方法。
谢谢
答案 0 :(得分:1)
要解决您的问题,您可以创建一个自定义函数,该函数以指定格式返回date-30
和date-1
之间的随机日期,并将此函数应用于新数据框的重复日期:
import pandas as pd
import random
def get_randomized_str_date(input_str_date):
ub_date = pd.to_datetime(input_str_date, dayfirst=True) - pd.DateOffset(1)
lb_date = ub_date - pd.DateOffset(29)
dates_range = pd.date_range(lb_date, ub_date)
return random.choice(dates_range).strftime('%d/%m/%Y')
# Create sample DataFrame
data = {'date_1': ['01/09/2019', '02/09/2019', '03/09/2019'],
'count': [5, 4, 5]}
df = pd.DataFrame(data)
print(df)
# date_1 count
# 0 01/09/2019 5
# 1 02/09/2019 4
# 2 03/09/2019 5
# Preprocess created DataFrame
df_new = df.loc[df.index.repeat(df['count'])] # repeat each row n-times, where n stored in df['count']
df_new['date_2'] = df_new['date_1'].apply(lambda x: get_randomized_str_date(x)) # get random date for specified date
print(df_new)
# date_1 count date_2
# 0 01/09/2019 5 18/08/2019
# 0 01/09/2019 5 23/08/2019
# 0 01/09/2019 5 23/08/2019
# 0 01/09/2019 5 27/08/2019
# 0 01/09/2019 5 12/08/2019
# 1 02/09/2019 4 11/08/2019
# 1 02/09/2019 4 02/08/2019
# 1 02/09/2019 4 03/08/2019
# 1 02/09/2019 4 23/08/2019
# 2 03/09/2019 5 01/09/2019
# 2 03/09/2019 5 28/08/2019
# 2 03/09/2019 5 21/08/2019
# 2 03/09/2019 5 19/08/2019
# 2 03/09/2019 5 31/08/2019
更新
为避免date_2列中的日期重复,您可以执行以下操作:
对于date_1列中的每个唯一日期,您都可以创建一个满足您要求的日期生成器,对于date_1列中的每个日期出现,您都可以从生成器中生成一个与该日期对应的唯一日期:
def get_date_generator(input_str_date):
ub_date = pd.to_datetime(input_str_date, dayfirst=True) - pd.DateOffset(1)
lb_date = ub_date - pd.DateOffset(29)
dates_range = [date.strftime('%d/%m/%Y') for date in pd.date_range(lb_date, ub_date)]
np.random.shuffle(dates_range)
return (date for date in dates_range)
def process_date_iter(generator):
try:
next_date = generator.__next__()
except StopIteration:
next_date = np.nan
return next_date
dates_generators = {date: get_date_generator(date) for date in df['date_1'].unique()}
df_new = df.loc[df.index.repeat(df['count'])]
df_new['date_2'] = df_new['date_1'].apply(lambda x: process_date_iter(dates_generators[x]))
print(df_new)
# date_1 count date_2
# 0 01/09/2019 5 04/08/2019
# 0 01/09/2019 5 14/08/2019
# 0 01/09/2019 5 25/08/2019
# 0 01/09/2019 5 03/08/2019
# 0 01/09/2019 5 02/08/2019
# 1 02/09/2019 4 14/08/2019
# 1 02/09/2019 4 08/08/2019
# 1 02/09/2019 4 30/08/2019
# 1 02/09/2019 4 28/08/2019
# 2 03/09/2019 5 29/08/2019
# 2 03/09/2019 5 10/08/2019
# 2 03/09/2019 5 26/08/2019
# 2 03/09/2019 5 15/08/2019
# 2 03/09/2019 5 28/08/2019
答案 1 :(得分:0)
使用reindex
重复行,
df.reindex(df.index.repeat(df['count'])).reset_index(drop=True)
结果
date_1 count
0 01/09/2019 5
1 01/09/2019 5
2 01/09/2019 5
3 01/09/2019 5
4 01/09/2019 5
.. ... ...
130 14/09/2019 16
131 14/09/2019 16
132 14/09/2019 16
133 14/09/2019 16
134 14/09/2019 16
对于连续的,非重复的日期范围,
>>> df['date_2'] = df.apply(lambda x: pd.date_range(x['date_1'], periods=x['count']).to_list(), axis=1)
>>> df = df.explode('date_2')
>>> df
date_1 count date_2
0 01/09/2019 5 2019-01-09
0 01/09/2019 5 2019-01-10
0 01/09/2019 5 2019-01-11
0 01/09/2019 5 2019-01-12
0 01/09/2019 5 2019-01-13
.. ... ... ...
13 14/09/2019 16 2019-09-25
13 14/09/2019 16 2019-09-26
13 14/09/2019 16 2019-09-27
13 14/09/2019 16 2019-09-28
13 14/09/2019 16 2019-09-29
[135 rows x 3 columns]
答案 2 :(得分:0)
这是上一个答案的替代方法(更基本),用于扩展第一列:
df_new=pd.DataFrame()
l=[]
for i,r in df.iterrows():
for j in range(df.loc[i,'count']):
l.append(r.date_1)
df_new.date_1=l
print(df_new)
然后您可以使用 .apply 和您的函数来定义新列...