提问人:Meera s 提问时间:11/11/2023 最后编辑:OCaMeera s 更新时间:11/19/2023 访问量:223
汇总数据帧特征的替代方法(嵌套循环、groupby)
Alternative ways to summarize dataframe feature (nested for loops, groupby)
问:
下面的数据框表示一个月的客户存在,粒度为 1 小时。存在时间记录为两列和 。 是月份中的某一天,是一天中的小时数。"REGIS_DAY"
"REGIS_HOUR"
"REGIS_DAY"
"REGIS_HOUR"
REGIS_DAY REGIS_HOUR REGIS_DATE REGIS_TIME
7 16 7/10/2011 16:21:05
3 3 3/10/2011 3:57:45
16 4 16/10/2011 4:08:47
24 3 24/10/2011 3:09:47
29 13 29/10/2011 13:43:40
7 16 7/10/2011 16:41:05
3 3 3/10/2011 3:24:45
3 3 3/10/2011 3:24:00
29 13 29/10/2011 13:43:01
29 13 29/10/2011 13:10:40
29 13 29/10/2011 13:20:40
输入数据: (df.to_dict()
)
{'REGIS_DAY': {0: '7', 1: '3', 2: '16', 3: '24', 4: '29', 5: '7', 6: '3', 7: '3', 8: '29', 9: '29', 10: '29'},
'REGIS_HOUR': {0: '16', 1: '3', 2: '4', 3: '3', 4: '13', 5: '16', 6: '3', 7: '3', 8: '13', 9: '13', 10: '13'},
'REGIS_DATE': {0: '7/10/2011', 1: '3/10/2011', 2: '16/10/2011', 3: '24/10/2011', 4: '29/10/2011', 5: '7/10/2011', 6: '3/10/2011', 7: '3/10/2011', 8: '29/10/2011', 9: '29/10/2011', 10: '29/10/2011'},
'REGIS_TIME': {0: '16:21:05', 1: '3:57:45', 2: '4:08:47', 3: '3:09:47', 4: '13:43:40', 5: '16:41:05', 6: '3:24:45', 7: '3:24:00', 8: '13:43:01', 9: '13:10:40', 10: '13:20:40'}}
在此任务中,我需要通过循环计算每小时同时在场的客户数量。因此,我每天(即 31 小时)和每 24 小时迭代一次:for
data_3124 = np.zeros((31,24), dtype = float)
for i in range(31):
for j in range(24):
number = (df.REGIS_DAY == (i+1)) & (df.REGIS_HOUR == j)
data_3124[i,j] = number.sum()
问题:上面的代码为所有值返回 0。
预期输出:
REGIS_DAY REGIS_HOUR sum
7 16 2
3 3 3
29 13 4
16 4 1
24 3 1
这就像在第 7 天和第 16 小时一样,同时在场的客户总数为 2 人;同样,在第 3 天和第 3 小时,有 3 名客户。
我也尝试过这个功能。我知道我找到解决方案的方式是错误的。.isin
其他信息:
OCa 和 Kirill Kondratenko 的无循环解决方案
df_result = (df_2011
.groupby(['REGIS_DAY', 'REGIS_HOUR'])
.size()
.reset_index()
.rename(columns={0:'sum'}))
和
df1 = df_2011.groupby(by=['REGIS_DAY','REGIS_HOUR'], as_index=False).size()
产量低于预期/正确的结果。那么,为什么我的嵌套循环方法总和总是 0?
答:
看起来你需要:
df = (df
.groupby(['REGIS_DAY', 'REGIS_HOUR'])
.size()
.reset_index()
.rename(columns={0:'sum'}))
print(df)
输出:
REGIS_DAY REGIS_HOUR sum
0 3 3 3
1 7 16 2
2 16 4 1
3 24 3 1
4 29 13 4
如果仍要使用循环,请使用:
REGIS_DAY = []
REGIS_HOUR = []
sum = []
for i in range(31):
for j in range(24):
REGIS_DAY.append(i)
REGIS_HOUR.append(j)
sum.append(len(df[(df['REGIS_DAY'] == i) & (df['REGIS_HOUR'] == j)]))
df_new = pd.DataFrame({'REGIS_DAY': REGIS_DAY,
'REGIS_HOUR': REGIS_HOUR,
'sum': sum})
评论
1. 正确设置数据类型
您正在将数值方法应用于仅包含字符串的数据。这就是为什么您的尝试返回空表的原因。整数将不匹配 string 。虽然某些方法不关心数据类型(请参阅下面的方法),但 numpy 数组上的嵌套循环确实需要实际数字。因此,您必须从以下数据类型转换开始:1
'1'
groupby
df[['REGIS_DAY','REGIS_HOUR']] = df[['REGIS_DAY','REGIS_HOUR']].astype('int')
df.dtypes
REGIS_DAY int32
REGIS_HOUR int32
REGIS_DATE object
REGIS_TIME object
dtype: object
现在你可以工作了。
有关该主题的更多信息,请参阅例如更改 pandas 中的列类型
2. 关于您的第一次尝试
您的代码片段已正确编写,并返回预期的 31*24 数组。它看起来不是收集数据的最便捷方式,以便您可以进一步使用它们。
# This was fine all along:
data_3124 = np.zeros((31,24), dtype = float)
for i in range(31):
for j in range(24):
number = (df.REGIS_DAY == (i+1)) & (df.REGIS_HOUR == j)
data_3124[i,j] = number.sum()
您可以通过几次检查来探测它:
data_3124.sum()
11
# This is indeed the number of rows in the initial dataframe
data_3124[6,16]
2.0
# Number of hits for day 7, hour 16.
3. pythonic 的做事方式
现在,它需要一行来定义另一个数据帧,就像您需要的那样:(不需要从字符串转换为整数即可工作)groupby
df1 = df.groupby(by=['REGIS_DAY','REGIS_HOUR'], as_index=False).size()
REGIS_DAY REGIS_HOUR size
0 3 3 3
1 7 16 2
2 16 4 1
3 24 3 1
4 29 13 4
如果您仍然想通过循环解决这个问题,我们也可以研究一下,但要知道这将是推荐的方法。
如需进一步阅读,您可以尝试: Pandas sum by groupby,但排除某些列
4. 嵌套循环的建议
接下来是一个可能更适合您当前任务的解决方案。它还会产生您想要的输出。同样,这需要事先将字符串转换为整数,如答案的第一部分所述。
这里的原则是以单行数据帧的形式填充每个点击(有客户在场的小时)的列表,然后将所有点击重新组合到一个最终的数据帧中(不太关心代码效率)。
df_list = []
for i in range(31):
for j in range(24):
# view dataframe subset meeting condition
df_ij = df.loc[(df['REGIS_DAY']==i+1) & (df['REGIS_HOUR']==j)]
# its number of rows
s_ij = len(df_ij)
# assign it to table
if s_ij>0:
df_list.append(pd.DataFrame({'REGIS_DAY' : [i],
'REGIS_HOUR' : [j],
'sum' : [s_ij]}))
# Concatenate the list of dataframes into a single table.
pd.concat(df_list, axis=0)
REGIS_DAY REGIS_HOUR sum
0 2 3 3
0 6 16 2
0 15 4 1
0 23 3 1
0 28 13 4
为了进一步阅读,我建议创建一个空的 Pandas DataFrame,然后填充它
对于良好的做法,请避免将列命名为 pandas 函数。这里是 sum
,因为语法 df.sum
可能无法提供您期望的内容。将列命名为“Sum”足以消除歧义。
评论