计算列中值的 3 个月滚动计数 Pandas
Calculate 3 Month Rolling Count of values in a column Pandas
我有以下数据框(这是数据框的简化版本,但逻辑是一样的):
#MONTH = yyyy-mm-dd
MONTH User
0 2021-04-01 A
1 2021-04-01 B
2 2021-05-01 B
3 2021-06-01 A
4 2021-06-01 B
5 2021-07-01 A
6 2021-07-01 B
7 2021-08-01 A
8 2021-08-01 B
我想要的是计算用户是否在 3 个月的滚动基础上活跃。
例如,用户 B
如果我们考虑 6 月 (2021-06-01),我们可以看到他在 5 月和 4 月活跃,因此在 3M 滚动基础上,他在 6 月被视为活跃。而用户 A
在同一时间段内,在三个月中有一个月没有活跃,因此他在 6 月将不被视为活跃。
期望的输出是有一个列计算每个月的活跃用户(300 万滚动),例如基于以上数据:
MONTH Active_User_Count
0 2021-04-01 NaN
1 2021-05-01 NaN
2 2021-06-01 1
3 2021-07-01 1
4 2021-08-01 2
我仍在努力了解滚动数据,所以如果有人可以帮助我,那就太好了!提前致谢!
EDIT MONTH
列只有每个月第一天的值,但那天有多个用户。所以没有2021-04-30,都是按月算的第一天。
好吧,让我们试试这个。
假设一个名为 df
的 pandas.DataFrame
,它有一个 MONTH
类型的列 pandas.Timestamp
,以及一个 User
列,我们可以 groupby
:
import pandas as pd
import numpy as np
df = #[however you got your data here]
df.MONTH = df.MONTH.apply(pd.Timestamp)
所以例如
>>> df
MONTH User
0 2021-04-01 A
1 2021-04-01 B
2 2021-05-01 B
3 2021-06-01 A
4 2021-06-01 B
5 2021-07-01 A
6 2021-07-01 B
7 2021-08-01 A
8 2021-08-01 B
然后根据以上内容,让我们制作一个DataFrame来保存我们的结果,从输入的开始到结束连续月份DataFrame
,并将活跃用户计数列初始化为0:
res = pd.DataFrame(pd.date_range(df.MONTH.min(),df.MONTH.max(),freq='MS'),columns=['MONTH'])
res['Active_User_Count'] = 0
res = res.set_index('MONTH').sort_index()
现在添加值:
for user, frame in df.groupby(by='User'):
# make a helper column, that has an indicator of whether the user
# was active that month (value='both') or not (value='right_only')
frame = frame.merge(
pd.Series(pd.date_range(start=frame.MONTH.min(),\
end=frame.MONTH.max(),\
freq='MS'),\
name='MONTH'),\
on='MONTH',how='outer',indicator=True)\
.set_index('MONTH').sort_index()
# this is where the magic happens;
# categorize the '_merge' results (0 = left_only, 1 = right_only, 2 = both)
# then on a 3-wide rolling window, get the minimum value
# check that it is greater than 1.5 (i.e. all three prev months
# are _merge value 'both')
# if it's not > 1.5, then the user wasn't active for all 3 months
# finally take the result from that rolling.min.apply,
# and funnel into a numpy.where array, which sets
# 'Active_User_Count' of the in-process user frame
# to an array of 1s and 0s
frame['Active_User_Count'] = np.where(
(frame._merge
.astype('category').cat.codes
.rolling(3).min().apply(lambda x: x > 1.5)), 1, 0)
# add the current-user activity into the total result
res.Active_User_Count[frame.index] += frame.Active_User_Count
# some re-formatting
res = res.reset_index().sort_index()
毕竟我们得到了输出:
>>> res
MONTH Active_User_Count
0 2021-04-01 0
1 2021-05-01 0
2 2021-06-01 1
3 2021-07-01 1
4 2021-08-01 2
TL;DR
这是一个函数来做这件事
import pandas as pd
import numpy as np
def active_users(df):
res = pd.DataFrame(pd.date_range(df.MONTH.min(),\
df.MONTH.max(),\
freq='MS'),\
columns=['MONTH'])
res['Active_User_Count'] = 0
res = res.set_index('MONTH').sort_index()
for user, frame in df.groupby(by='User'):
frame = frame.merge(pd.Series(
pd.date_range(start=frame.MONTH.min(),\
end=frame.MONTH.max(),\
freq='MS'),\
name='MONTH'),\
on='MONTH',\
how='outer',\
indicator=True)\
.set_index('MONTH').sort_index()
frame['Active_User_Count'] = np.where(
(frame._merge
.astype('category')
.cat.codes
.rolling(3).min().apply(lambda x: x > 1.5)), 1, 0)
res.Active_User_Count[frame.index] += frame.Active_User_Count
return res.reset_index().sort_index()
我有以下数据框(这是数据框的简化版本,但逻辑是一样的):
#MONTH = yyyy-mm-dd
MONTH User
0 2021-04-01 A
1 2021-04-01 B
2 2021-05-01 B
3 2021-06-01 A
4 2021-06-01 B
5 2021-07-01 A
6 2021-07-01 B
7 2021-08-01 A
8 2021-08-01 B
我想要的是计算用户是否在 3 个月的滚动基础上活跃。
例如,用户 B
如果我们考虑 6 月 (2021-06-01),我们可以看到他在 5 月和 4 月活跃,因此在 3M 滚动基础上,他在 6 月被视为活跃。而用户 A
在同一时间段内,在三个月中有一个月没有活跃,因此他在 6 月将不被视为活跃。
期望的输出是有一个列计算每个月的活跃用户(300 万滚动),例如基于以上数据:
MONTH Active_User_Count
0 2021-04-01 NaN
1 2021-05-01 NaN
2 2021-06-01 1
3 2021-07-01 1
4 2021-08-01 2
我仍在努力了解滚动数据,所以如果有人可以帮助我,那就太好了!提前致谢!
EDIT MONTH
列只有每个月第一天的值,但那天有多个用户。所以没有2021-04-30,都是按月算的第一天。
好吧,让我们试试这个。
假设一个名为 df
的 pandas.DataFrame
,它有一个 MONTH
类型的列 pandas.Timestamp
,以及一个 User
列,我们可以 groupby
:
import pandas as pd
import numpy as np
df = #[however you got your data here]
df.MONTH = df.MONTH.apply(pd.Timestamp)
所以例如
>>> df
MONTH User
0 2021-04-01 A
1 2021-04-01 B
2 2021-05-01 B
3 2021-06-01 A
4 2021-06-01 B
5 2021-07-01 A
6 2021-07-01 B
7 2021-08-01 A
8 2021-08-01 B
然后根据以上内容,让我们制作一个DataFrame来保存我们的结果,从输入的开始到结束连续月份DataFrame
,并将活跃用户计数列初始化为0:
res = pd.DataFrame(pd.date_range(df.MONTH.min(),df.MONTH.max(),freq='MS'),columns=['MONTH'])
res['Active_User_Count'] = 0
res = res.set_index('MONTH').sort_index()
现在添加值:
for user, frame in df.groupby(by='User'):
# make a helper column, that has an indicator of whether the user
# was active that month (value='both') or not (value='right_only')
frame = frame.merge(
pd.Series(pd.date_range(start=frame.MONTH.min(),\
end=frame.MONTH.max(),\
freq='MS'),\
name='MONTH'),\
on='MONTH',how='outer',indicator=True)\
.set_index('MONTH').sort_index()
# this is where the magic happens;
# categorize the '_merge' results (0 = left_only, 1 = right_only, 2 = both)
# then on a 3-wide rolling window, get the minimum value
# check that it is greater than 1.5 (i.e. all three prev months
# are _merge value 'both')
# if it's not > 1.5, then the user wasn't active for all 3 months
# finally take the result from that rolling.min.apply,
# and funnel into a numpy.where array, which sets
# 'Active_User_Count' of the in-process user frame
# to an array of 1s and 0s
frame['Active_User_Count'] = np.where(
(frame._merge
.astype('category').cat.codes
.rolling(3).min().apply(lambda x: x > 1.5)), 1, 0)
# add the current-user activity into the total result
res.Active_User_Count[frame.index] += frame.Active_User_Count
# some re-formatting
res = res.reset_index().sort_index()
毕竟我们得到了输出:
>>> res
MONTH Active_User_Count
0 2021-04-01 0
1 2021-05-01 0
2 2021-06-01 1
3 2021-07-01 1
4 2021-08-01 2
TL;DR
这是一个函数来做这件事
import pandas as pd
import numpy as np
def active_users(df):
res = pd.DataFrame(pd.date_range(df.MONTH.min(),\
df.MONTH.max(),\
freq='MS'),\
columns=['MONTH'])
res['Active_User_Count'] = 0
res = res.set_index('MONTH').sort_index()
for user, frame in df.groupby(by='User'):
frame = frame.merge(pd.Series(
pd.date_range(start=frame.MONTH.min(),\
end=frame.MONTH.max(),\
freq='MS'),\
name='MONTH'),\
on='MONTH',\
how='outer',\
indicator=True)\
.set_index('MONTH').sort_index()
frame['Active_User_Count'] = np.where(
(frame._merge
.astype('category')
.cat.codes
.rolling(3).min().apply(lambda x: x > 1.5)), 1, 0)
res.Active_User_Count[frame.index] += frame.Active_User_Count
return res.reset_index().sort_index()