Pandas层级透视表:获取各date-hr下计数最大的Channel
Pandas透视表转换:提取每个date-hr下计数最高的Channel及计数值
没问题,我来帮你搞定这个数据转换需求。先咱们对齐一下数据情况和目标,然后一步步实现:
数据背景回顾
你的原始DataFrame结构如下:
df.head().info()
输出:
RangeIndex: 5 entries, 0 to 4 Data columns (total 4 columns): id 5 non-null object date-hr 5 non-null object channel 5 non-null object hr 5 non-null int64 dtypes: int64(1), object(3)
数据样例(简化后):
User-ID | Date-hr | Channel | Hr U1 | D1-10 | C1 | 10 U1 | D1-11 | C2 | 11 U1 | D1-10 | C1 | 10 U1 | D1-10 | C3 | 10 U1 | D1-10 | C1 | 10 U1 | D1-11 | C3 | 11 U1 | D1-11 | C2 | 11 ...
你已经完成了第一步透视,得到了每个用户、每个date-hr下不同channel的计数,现在需要把每个date-hr列转换为该时段内计数最高的channel + 对应计数值的元组格式。
方法一:基于透视表分组处理
这是最直接的思路,先构建基础透视表,再对每个date-hr列组提取最大值信息:
import pandas as pd # 1. 构建基础透视表:行是User-ID,列是(date-hr, channel),值是计数 pivot_df = df.pivot_table( index='id', columns=['date-hr', 'channel'], values='hr', aggfunc='count', fill_value=0 ) # 2. 定义函数:对单个date-hr下的所有channel列,提取每行的最大计数及对应channel def get_top_channel_info(col_group): # col_group是当前date-hr下的所有channel列组成的DataFrame max_counts = col_group.max(axis=1) # 找到计数最大的channel:idxmax返回的是(date-hr, channel)索引,取第二个元素 top_channels = col_group.idxmax(axis=1).str[1] # 组合成元组 return pd.Series(list(zip(top_channels, max_counts)), index=col_group.index) # 3. 按date-hr列分组(第一层列索引),应用函数 result_df = pivot_df.groupby(level=0, axis=1).apply(get_top_channel_info)
运行后result_df的格式就完全符合你的需求了,比如U1行的D1-10列会是('C1', 3),D1-11列是('C2', 2)。
方法二:堆叠透视表后再重组
如果你觉得分组处理有点绕,也可以用“堆叠-提取-重组”的思路:
import pandas as pd # 1. 先做基础透视表(和方法一一样) pivot_df = df.pivot_table( index='id', columns=['date-hr', 'channel'], values='hr', aggfunc='count', fill_value=0 ) # 2. 把date-hr从列索引转到行索引,变成(id, date-hr)为复合索引,channel为列 stacked_df = pivot_df.stack(level=0) # 3. 提取每个(id, date-hr)组合下的最大计数channel和对应值 top_channels = stacked_df.idxmax(axis=1) top_counts = stacked_df.max(axis=1) # 4. 组合成元组,再重新透视回date-hr为列的格式 result_df = pd.DataFrame( {'top_info': list(zip(top_channels, top_counts))}, index=stacked_df.index ).unstack(level=1) # 5. 去掉多余的顶层列名(因为unstack后会有'top_info'作为顶层列) result_df.columns = result_df.columns.droplevel(0)
这个方法的逻辑更直观:先把date-hr放到行里,让每个用户+时段的组合独立成行,找到最大值后再把date-hr转回列。
两种方法都能得到你想要的结果,你可以根据自己的习惯选择。如果你的数据量很大,方法一的效率会稍微高一点,因为不需要频繁转换索引结构。
内容的提问来源于stack exchange,提问作者Nikhil Verma
相关产品推荐
相关产品推荐

