如何在 Python 中创建日期时间使用跟踪器?
How to create a date time usage tracker in Python?
我正在尝试创建一个使用跟踪器来标记在最后一次标记 ID 后 14 天内具有相同 ID 的项目。因此,如果相同的 ID 在第一个 ID 没有标记后的 14 天内出现,如果它在第一个标记后的 14 天之外出现,那么它将成为每个 ID 的第二个标记。
我试过使用 .ffill() .groupby .rolling
这些有助于在 14 天内找到重复项,但对滚动标志没有帮助。我认为解决方案可能在于 for
循环的某个时间和扩展的 window?
起始码
df:
date id
1/1/19 38
1/5/19 16
1/10/19 38
1/15/19 38
1/21/19 38
1/30/19 16
2/2/19 38
2/2/19 38
2/3/19 38
我需要得到什么
df2:
date id flag most recent flag
1/1/19 38 True 1/1/19
1/5/19 16 True 1/5/19
1/10/19 38 False 1/1/19
1/15/19 38 True 1/15/19
1/21/19 38 False 1/15/19
1/30/19 16 True 1/30/19
2/2/19 38 True 2/2/19
2/2/19 38 False 2/2/19
2/3/19 38 False 2/2/19
这种问题很复杂,因为标记取决于最后一个,可以是之前的任意行数。我认为您需要创建自己的函数来获取每组 id 的 True
,但首先要确保日期列是日期时间。然后你可以这样做:
df.date = pd.to_datetime(df.date)
def create_flag(x, nb_days = 14):
# calculate the delta in days with the first value
arr = (x - x.min()).dt.days.values
# create an array to get the flags
flag = np.zeros_like(arr, dtype=bool)
# change the first value
flag[0] = True
# iterate over the all data
for i in range(1, len(arr)):
# once over xx days
if arr[i] >= nb_days:
#remove this value to the rest of the arr to restart the count from this flag
arr[i:] -= arr[i]
# add the flag to true
flag[i] = True
return pd.DataFrame( {'flag':flag, 'last_flag': x[flag]}, # mask x with flag to get the date of flagging
index=x.index).ffill() # ffill for the date
df[['flag','last_flag']] = df.groupby('id').date.apply(create_flag)
print (df)
date id flag last_flag
0 2019-01-01 38 True 2019-01-01
1 2019-01-05 16 True 2019-01-05
2 2019-01-10 38 False 2019-01-01
3 2019-01-15 38 True 2019-01-15
4 2019-01-21 38 False 2019-01-15
5 2019-01-30 16 True 2019-01-30
6 2019-02-02 38 True 2019-02-02
7 2019-02-02 38 False 2019-02-02
8 2019-02-03 38 False 2019-02-02
抱歉让您久等了
这里是生成df的代码如上图
df = pd.DataFrame({
'date':['1/1/19','1/5/19','1/10/19','1/15/19','1/21/19','1/30/19','2/2/19','2/2/19','2/3/19'],
'id':[38,16,38,38,38,16,38,38,38]
})
df['date'] = pd.to_datetime(df['date'])
而且,这些是我在计算您的标志之前创建的其他列
df['days_ago'] = df.groupby('id')['date'].diff()\
.fillna(pd.Timedelta(seconds=0)).astype('timedelta64[D]').astype(int)
df['days_ago_cumsum'] = df.groupby('id')['days_ago'].cumsum()
而且,这是计算那个标志的函数
def get_fixed_day_flag(days_ago_cumsum, within=14):
while True:
cond = days_ago_cumsum >= within
days_ago_cumsum_min = days_ago_cumsum.where(cond).min()
new_days_ago_cumsum = days_ago_cumsum.where(cond) - days_ago_cumsum_min
cond = new_days_ago_cumsum.notna()
days_ago_cumsum[cond] = new_days_ago_cumsum[cond].astype(int)
if days_ago_cumsum.max() < within:
return days_ago_cumsum == 0
然后,完成这两行
df['flag'] = df.groupby('id')['days_ago_cumsum'].transform(get_fixed_day_flag)
df['flag'] = df['flag'] & ~df.duplicated(subset=['date','id'])
我正在尝试创建一个使用跟踪器来标记在最后一次标记 ID 后 14 天内具有相同 ID 的项目。因此,如果相同的 ID 在第一个 ID 没有标记后的 14 天内出现,如果它在第一个标记后的 14 天之外出现,那么它将成为每个 ID 的第二个标记。
我试过使用 .ffill() .groupby .rolling
这些有助于在 14 天内找到重复项,但对滚动标志没有帮助。我认为解决方案可能在于 for
循环的某个时间和扩展的 window?
起始码
df:
date id
1/1/19 38
1/5/19 16
1/10/19 38
1/15/19 38
1/21/19 38
1/30/19 16
2/2/19 38
2/2/19 38
2/3/19 38
我需要得到什么
df2:
date id flag most recent flag
1/1/19 38 True 1/1/19
1/5/19 16 True 1/5/19
1/10/19 38 False 1/1/19
1/15/19 38 True 1/15/19
1/21/19 38 False 1/15/19
1/30/19 16 True 1/30/19
2/2/19 38 True 2/2/19
2/2/19 38 False 2/2/19
2/3/19 38 False 2/2/19
这种问题很复杂,因为标记取决于最后一个,可以是之前的任意行数。我认为您需要创建自己的函数来获取每组 id 的 True
,但首先要确保日期列是日期时间。然后你可以这样做:
df.date = pd.to_datetime(df.date)
def create_flag(x, nb_days = 14):
# calculate the delta in days with the first value
arr = (x - x.min()).dt.days.values
# create an array to get the flags
flag = np.zeros_like(arr, dtype=bool)
# change the first value
flag[0] = True
# iterate over the all data
for i in range(1, len(arr)):
# once over xx days
if arr[i] >= nb_days:
#remove this value to the rest of the arr to restart the count from this flag
arr[i:] -= arr[i]
# add the flag to true
flag[i] = True
return pd.DataFrame( {'flag':flag, 'last_flag': x[flag]}, # mask x with flag to get the date of flagging
index=x.index).ffill() # ffill for the date
df[['flag','last_flag']] = df.groupby('id').date.apply(create_flag)
print (df)
date id flag last_flag
0 2019-01-01 38 True 2019-01-01
1 2019-01-05 16 True 2019-01-05
2 2019-01-10 38 False 2019-01-01
3 2019-01-15 38 True 2019-01-15
4 2019-01-21 38 False 2019-01-15
5 2019-01-30 16 True 2019-01-30
6 2019-02-02 38 True 2019-02-02
7 2019-02-02 38 False 2019-02-02
8 2019-02-03 38 False 2019-02-02
抱歉让您久等了
这里是生成df的代码如上图
df = pd.DataFrame({
'date':['1/1/19','1/5/19','1/10/19','1/15/19','1/21/19','1/30/19','2/2/19','2/2/19','2/3/19'],
'id':[38,16,38,38,38,16,38,38,38]
})
df['date'] = pd.to_datetime(df['date'])
而且,这些是我在计算您的标志之前创建的其他列
df['days_ago'] = df.groupby('id')['date'].diff()\
.fillna(pd.Timedelta(seconds=0)).astype('timedelta64[D]').astype(int)
df['days_ago_cumsum'] = df.groupby('id')['days_ago'].cumsum()
而且,这是计算那个标志的函数
def get_fixed_day_flag(days_ago_cumsum, within=14):
while True:
cond = days_ago_cumsum >= within
days_ago_cumsum_min = days_ago_cumsum.where(cond).min()
new_days_ago_cumsum = days_ago_cumsum.where(cond) - days_ago_cumsum_min
cond = new_days_ago_cumsum.notna()
days_ago_cumsum[cond] = new_days_ago_cumsum[cond].astype(int)
if days_ago_cumsum.max() < within:
return days_ago_cumsum == 0
然后,完成这两行
df['flag'] = df.groupby('id')['days_ago_cumsum'].transform(get_fixed_day_flag)
df['flag'] = df['flag'] & ~df.duplicated(subset=['date','id'])