【问题标题】:Generate data for dates based on a constraint根据约束生成日期数据
【发布时间】:2019-11-03 10:38:58
【问题描述】:

我有一个数据框 df1,其中包含 date_1 列,其值从 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,这样:

  1. 有一个新列 date_2。

  2. date_2 是根据 df1 中存在的计数特征生成的。

例如:一个新的数据框 df2 有 5 个条目(因为 count = 5),用于 01/09/2019,并且 date_2 列可以采用 date_1 之前 30 天到 2019 年 8 月 30 日之间的值(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

date_2 可以从范围(30 - date_1date_1 - 1)中随机选择,即在我们的示例中为 01/09/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 生成相同的增量,从而导致重复条目。我不想生成重复的条目。 *

任何人都可以提出一种生成相同的方法。

谢谢

【问题讨论】:

  • 你试过什么? @vp7
  • @Vishnudev 我能够根据生成 1-30 的随机增量并基于此生成 date_2 来生成随机范围,但我无法理解如何根据计数。
  • @Vishnudev 我已经使用我为生成相同问题而编写的函数编辑了问题

标签: python pandas numpy


【解决方案1】:

为了解决您的问题,您可以创建一个自定义函数,以指定格式返回 date-30date-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

【讨论】:

  • 感谢您的回答,但我不想要 date_2 中的随机日期。 date_2 应在 (date_1 - 30) 天到 (date_1 -1) 天之间生成。并且条目也不应重复。你能根据那个编辑你的答案吗?
  • 结果中生成的值对于 date_2 不正确。如果您看到,对于 01/09/2019,生成的 date_2 是 11/12/2018,这是不正确的
  • 你好@vp7!更改正确的日期预处理。需要时间考虑如何为每个日期创建不可重复的随机日期。
  • @vp7,您可以看到有关如何避免在 date_2 列中重复的更新部分。
【解决方案2】:

使用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]

【讨论】:

  • 我这样做是第一步,然后应用我的函数来生成 date_2,这就是你的意思吗?
  • 对此还有一个疑问,如果我从我的函数生成,它是随机生成增量,同一日期有可能重复增量,我如何在我的函数中解决相同的问题?
  • 这不是我要找的……它正在连续打印日期。我希望将 date_2 从 date_1-30 随机化到 date_1-1 天。您的答案只是根据计数打印日期。我在问题中也提到过。你能检查一下吗?谢谢
【解决方案3】:

这是扩展第一列的先前答案的替代方案(更基本):

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 和您的函数来定义新列...

【讨论】:

    猜你喜欢
    • 2019-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-20
    相关资源
    最近更新 更多