基于列值重塑数据表:按分组与类型聚合并动态生成列
我来帮你解决这个kdb+里的动态列重塑问题!你的前期数据合并和聚合步骤已经做对了,接下来只需要完成长表转宽表+动态列名生成这两个关键环节,就能得到你想要的结果。
先回顾你的前期工作
你已经成功把V1/V2和对应Type合并成一个长表,过滤掉空Type并按Group+Type求和,这部分的tr表结构应该是这样的:
Group Type Value ---------------- 1 t1 10 1 t2 15 2 t1 30 2 t2 18 2 t3 15
(注:Group1的t2总和是ID2的V1=12 + ID1的V2=3;Group2的t1是ID3的14+ID4的16,t3是ID4的7+ID5的8,完全符合目标输出的数值)
完整解决方案步骤
1. 给每个Group内的Type分配组内序号
我们需要给每个Group里的Type分配唯一的序号(1、2、3...),用来生成v_n和type_n这类动态列名。这里用count i by Group按Type的出现顺序分配序号:
// 给tr表添加组内序号idx tr:update idx:1+count i by Group from tr;
此时tr的结构变成:
Group Type Value idx -------------------- 1 t1 10 1 1 t2 15 2 2 t1 30 1 2 t2 18 2 2 t3 15 3
2. 动态生成列名并转成宽表
利用kdb+的字典和分组功能,实现类似R中dcast的动态列生成:
// 生成每个行对应的v列和type列名称(比如v_1、type_1) tr:update v_col:`$"v_",string idx, type_col:`$"type_",string idx from tr; // 按Group分组,收集每个组的(列名,值)键值对 grouped_data:exec raze [(v_col; Value); (type_col; Type)] by Group from tr; // 把分组后的字典转成表,并按列名排序保证顺序正确 result:flip grouped_data; result:select Group, asc cols[1] from result;
执行完以上步骤后,result就完全匹配你的期望输出了:
Group v_1 type_1 v_2 type_2 v_3 type_3 --------------------------------------- 1 10 t1 15 t2 NA <NA> 2 30 t1 18 t2 15 t3
简化版一步到位代码
如果想把所有步骤合并成一段,可以这样写:
// 合并V1/V2数据、过滤空Type、求和 tr:0!select sum Value by Group, Type from (select Group, Value:V1, Type:Type_v1 from df), (select Group, Value:V2, Type:Type_v2 from df) where Type <> `; // 分配组内序号+生成动态列名+转宽表 result:flip exec raze [(`$"v_",string idx; Value); (`$"type_",string idx; Type)] by Group from update idx:1+count i by Group from tr; result:select Group, asc cols[1] from result;
关键逻辑解释
count i by Group:给每个Group内的行分配递增序号,确保每个Type在组内有唯一编号,为动态列名提供基础。raze [(v_col; Value); (type_col; Type)]:把每个行的v列和type列的键值对合并成列表,比如Group1的第一行会生成(v_1;10;type_1;`t1),最终每个Group的所有键值对会合并成一个大列表。flip grouped_data:把以Group为key的字典转置成表,自动将键作为列名、值作为列数据,实现长表转宽表。asc cols[1]:对除Group外的列按名称排序,保证v_1在type_1前、v_2在type_2前,列顺序符合预期。
这个方案完全支持动态生成任意数量的列,哪怕是20k列也能轻松处理,不需要手动输入任何列名!
内容的提问来源于stack exchange,提问作者Will
相关产品推荐
相关产品推荐

