gpt4 book ai didi

python - 根据超过 1 个约束生成日期

转载 作者:行者123 更新时间:2023-12-01 00:24:45 25 4
gpt4 key购买 nike

我有一个数据框 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

我想使用 df1 生成数据帧 df2,并具有一些约束:

  1. 有一个新列 date_2。

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

例如:新的数据框 df2 将在 01/09/2019 有 5 个条目(因为计数 = 5),并且 date_2 列可以采用 date_1 之前 30 天到 30/08/2019 的值(date_1 - 1 中的当前日期) ),即对于 01/09/2019,date_2 可以采用的值是从 (01/09/2019 - 30 = 01/08/2019) 到 (01/09/2019 - 1 = 30/08/2019)。

date_2 可以从范围(30 - date_1date_1 - 1)中随机选择,即在我们的示例中为 01/09/2019,从 02/08/2019年至2019年8月30日

需要注意的重要一点是,date_2 在 df2 中的计数也应该递增。

预期输出:

    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:

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 生成相同的增量,从而导致重复条目。我不想生成重复的条目。 *

我也无法理解如何根据计数复制数据框中的字段并相应地生成日期。

任何人都可以帮助/建议一种生成相同内容的方法。

谢谢

最佳答案

定义以下“复制”函数:

def repl(row):
d1 = row.date_1
cnt = row['count']
dates = [ d1 - pd.Timedelta(n, 'D') for n in
np.sort(np.random.choice(30, cnt, False))[::-1] ]
return pd.DataFrame({'date_1': d1, 'count': cnt, 'date_2': dates})

然后应用它,连接结果并保存为DF2:

DF2 = pd.concat(df.apply(repl, axis=1).tolist(), ignore_index=True)

请注意,上面代码中的row['count']可以被替换与 row.count,因为有一个 Pandas 具有此名称的方法。实际上,这只是分配列名称的示例。您不应该使用现有方法的名称。

编辑有关“所有值”的评论

要消耗该范围内的所有日期,过程更加复杂并且涉及创建一个专用类来从池中生成日期。

日期分配算法如下:

  • 日期池是在开始时创建的,从分钟日期 - 30 天到最大日期。
  • 每次通话时:
    • 第 1 步:获取第一个可能的日期。
    • 第 2 步:从池中获取更多日期。
    • 在这两个步骤中,指定的日期都会从池中删除。
    • 第 3 步:如果池中没有更多日期(在允许的范围内),但我们需要更多,从可能的范围生成日期,但没有重复迄今为止为此行选择的日期。

这个类还包含一个“技巧”,以弥补以下事实:第一行应用的函数被调用两次。这是 Pandas 中包含的一项优化,但在本例中它有一个副作用(消耗一些“初始”日期,这不是实际上包含在结果中),所以我必须对此进行补偿。

按如下方式进行:

创建一对在各个点使用的Timedelta变量:

td1 = pd.Timedelta(1, 'D')
td30 = pd.Timedelta(30, 'D')

然后定义一个日期生成器类:

class DateGen:
''' Dates generator
d1, d2 - date range
'''
def __init__(self, d1, d2):
rng = pd.date_range(d1, d2, freq='D')
self.dates = pd.Series(rng, index=rng)
self.firstCall = True

def popDate(self, d1, d2):
wrk = self.dates[self.dates.between(d1, d2)]
siz = wrk.size
if siz > 0:
dat = wrk.sample().iloc[0] if siz > 1 else wrk.iloc[0]
self.dates.pop(dat)
return dat, True
return None, False

def popDates(self, d1, d2, n):
ret = []
if self.firstCall:
self.firstCall = False
return ret
# Step 1: Get the first possible date
dat, ok = self.popDate(d1, d1)
if ok:
ret.append(dat)
# Step 2: Get further dates not consumed so far
while len(ret) < n:
dat, ok = self.popDate(d1, d2)
if not ok:
break
ret.append(dat)
# Step 3: Repeat dates already consumed
while len(ret) < n:
shft = np.random.randint(30)
dat = d2 - pd.Timedelta(shft, 'D')
if dat not in ret: # Without repetitions
ret.append(dat)
return ret

根据日期实例化该类的具有日期范围的对象在DF1中:

dg = DateGen(DF1.date_1.min() - td30, DF1.date_1.max())

这次的复制功能有点不同:

def repl(row):
d1 = row.date_1
cnt = row['count']
dates = np.sort(dg.popDates(d1 - td30, d1 - td1, cnt))
return pd.DataFrame({'date_1': d1, 'count': cnt, 'date_2': dates})

它从生成器对象中弹出日期,然后对它们进行排序并返回在返回的 DataFrame 中。

最后一步是应用它:

DF2 = pd.concat(DF1.sort_values('date_1').\
apply(repl, axis=1).tolist(), ignore_index=True)

因为现在日期顺序很重要,所以我首先按 date_1 排序。

关于python - 根据超过 1 个约束生成日期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58681380/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com