【问题标题】:Creating fake data using date logic使用日期逻辑创建假数据
【发布时间】:2021-07-25 22:48:15
【问题描述】:

我正在尝试在此表中插入虚假数据。它不能完全随机,因为行需要有意义。我会在下面解释。

我的数据如下所示:

AcctID account_status start_date end_date
C382861922 ACTIVE 2016-05-25 None
C382861922 INACTIVE None None
C382861922 ACTIVE None None
C382861922 INACTIVE None 2021-12-31
C429768513 ACTIVE 2015-12-27 None
C429768513 INACTIVE None None
C429768513 ACTIVE None None
C429768513 INACTIVE None None
C429768513 ACTIVE None None
C429768513 INACTIVE None None
C429768513 ACTIVE None None
C429768513 INACTIVE None 2021-12-31
C643625629 ACTIVE 2016-07-24 None
C643625629 INACTIVE None None
C643625629 ACTIVE None 2021-12-31
C82157435 ACTIVE 2016-10-22 None
C82157435 INACTIVE None 2021-12-31

每个 AcctID 可以出现多次,但最简单的方法是通过 AcctID 出现两次的示例来解释我在做什么:

AcctID account_status start_date end_date
C82157435 ACTIVE 2016-10-22 None
C82157435 INACTIVE None 2021-12-31

我的目标是随机选择一个日期,该客户更改其 account_status 的日期,将成为第一行的 end_date 和第二行的 start_date。所以,我只需要选择 1 个随机日期,并将其插入两个地方。很简单 - 我可以 max() 和 min() 然后计算天数的差异,然后在该范围内选择一个随机整数。

但是,我不知道如何为使用超过 2 条记录的客户做这件事

AcctID account_status start_date end_date
C429768513 ACTIVE 2015-12-27 None
C429768513 INACTIVE None None
C429768513 ACTIVE None None
C429768513 INACTIVE None None
C429768513 ACTIVE None None
C429768513 INACTIVE None None
C429768513 ACTIVE None None
C429768513 INACTIVE None 2021-12-31

会有好几个地方随机选择日期,但是由于需要相互对应,问题就变得很复杂了。有什么想法吗?

创建示例数据框的代码如下:

import pandas as pd

fake = [
 {
   "AcctID": "C429768513",
   "account_status": "ACTIVE",
   "start_date": "2015-12-27",
   "end_date": "None"
 },
 {
   "AcctID": "C429768513",
   "account_status": "INACTIVE",
   "start_date": "None",
   "end_date": "None"
 },
 {
   "AcctID": "C429768513",
   "account_status": "ACTIVE",
   "start_date": "None",
   "end_date": "None"
 },
 {
   "AcctID": "C429768513",
   "account_status": "INACTIVE",
   "start_date": "None",
   "end_date": "None"
 },
 {
   "AcctID": "C429768513",
   "account_status": "ACTIVE",
   "start_date": "None",
   "end_date": "None"
 },
 {
   "AcctID": "C429768513",
   "account_status": "INACTIVE",
   "start_date": "None",
   "end_date": "None"
 },
 {
   "AcctID": "C429768513",
   "account_status": "ACTIVE",
   "start_date": "None",
   "end_date": "None"
 },
 {
   "AcctID": "C429768513",
   "account_status": "INACTIVE",
   "start_date": "None",
   "end_date": "2021-12-31"
 }
]

df = pd.DataFrame(fake)

编辑: 这是程序输出的一个假例子。请注意,大多数日期是随机选择的 - 但前一行的结束日期与下一行的开始日期匹配。

AcctID account_status start_date end_date
C429768513 ACTIVE 2015-12-27 2016-01-05
C429768513 INACTIVE 2016-01-05 2016-03-01
C429768513 ACTIVE 2016-03-01 2017-06-22
C429768513 INACTIVE 2017-06-22 2017-09-04
C429768513 ACTIVE 2017-09-04 2018-10-27
C429768513 INACTIVE 2018-10-27 2019-04-04
C429768513 ACTIVE 2019-04-04 2020-06-06
C429768513 INACTIVE 2020-06-06 2021-12-31

【问题讨论】:

  • 我能想到的一件事是 groupby AcctID 并遍历每个组。注意索引,如果奇数则生成随机日期,将其添加为end_date,然后下一行(偶数索引)使用与start_date 相同的日期。并为该行生成一个以添加为end_date。不过要小心管理极端情况
  • 这个程序对一个帐户可能的输出是什么样的?

标签: python pandas dataframe python-datetime


【解决方案1】:

解决这个问题的一种方法:

df = df.replace(to_replace='None', value=np.nan)

def random_date(x):
    s_d = pd.to_datetime(x[x['start_date'].notna()]['start_date'])
    e_d = pd.to_datetime(x[x['end_date'].notna()]['end_date'])
    
    start_u = s_d.iloc[0].value//10**9
    end_u = e_d.iloc[0].value//10**9
    end_date_list = sorted(pd.to_datetime(np.random.randint(start_u, end_u, len(x)-1), unit='s').values)
    end_date_list = np.append(end_date_list, e_d.values)
    x['end_date'] = end_date_list
    mask = x['start_date'].isna()
    x.loc[mask,'start_date'] = x.shift(1).loc[mask]['end_date'].astype(str)
    x['start_date'] = pd.to_datetime(x['start_date']).dt.date
    x['end_date'] = pd.to_datetime(x['end_date']).dt.date
    return x

df = df.groupby('AcctID').apply(random_date)

输出:

        AcctID account_status  start_date    end_date
0   C382861922         ACTIVE  2016-05-25  2016-12-23
1   C382861922       INACTIVE  2016-12-23  2017-12-28
2   C382861922         ACTIVE  2017-12-28  2019-04-24
3   C382861922       INACTIVE  2019-04-24  2021-12-31
4   C429768513         ACTIVE  2015-12-27  2017-12-04
5   C429768513       INACTIVE  2017-12-04  2019-01-07
6   C429768513         ACTIVE  2019-01-07  2019-04-03
7   C429768513       INACTIVE  2019-04-03  2020-06-13
8   C429768513         ACTIVE  2020-06-13  2021-02-13
9   C429768513       INACTIVE  2021-02-13  2021-03-09
10  C429768513         ACTIVE  2021-03-09  2021-08-09
11  C429768513       INACTIVE  2021-08-09  2021-12-31
12  C643625629         ACTIVE  2016-07-24  2021-02-27
13  C643625629       INACTIVE  2021-02-27  2021-05-20
14  C643625629         ACTIVE  2021-05-20  2021-12-31
15   C82157435         ACTIVE  2016-10-22  2021-02-20
16   C82157435       INACTIVE  2021-02-20  2021-12-31

【讨论】:

  • 在这种情况下 start.value 是什么? start.value//10**9 它没有定义,但如果它指的是 s_d 那么这将是一个不适用于 .value 的系列
  • @Josh 修复了它。你现在可以试试吗
  • 这对我来说就像黑魔法,我已经很接近了,但它涉及 50 多行,但我还没有完成。太好了,谢谢
猜你喜欢
  • 2020-12-18
  • 1970-01-01
  • 1970-01-01
  • 2018-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-08
  • 1970-01-01
相关资源
最近更新 更多