使用awk实现多列字符串计数的长格式转宽格式
长格式转宽格式的字符串频次统计实现方案
核心适配逻辑
你之前写的awk代码是针对数值列做累加、按分组求平均的场景,无法满足当前需求的核心原因是没有加入「分组内不同字符串值的独立计数」逻辑,改造后的逻辑完全匹配需求:
- 以第一列的样本ID为一级分组维度
- 对第二、第三列的每个不同字符串值单独累加出现次数
- 遍历分组下的所有计数结果,按要求拼接成
出现次数_字符串格式,同列多个值用逗号分隔
方案1:原生awk实现(无需额外依赖,适配你当前的使用习惯)
直接替换原有命令即可,适配你提供的示例输入:
awk ' # 逐行读取原始数据 { sample = $1 # 统计第二列各字符串的出现次数:计数结构为 [样本ID][字符串值] = 累计次数 col2_cnt[sample][$2]++ # 统计第三列各字符串的出现次数:计数结构为 [样本ID][字符串值] = 累计次数 col3_cnt[sample][$3]++ } # 所有数据读取完成后输出结果 END { # 遍历每个样本的分组数据 for (sid in col2_cnt) { col2_str = "" # 拼接第二列的目标格式 for (str_val in col2_cnt[sid]) { col2_str = col2_str (col2_str ? "," : "") col2_cnt[sid][str_val] "_" str_val } col3_str = "" # 拼接第三列的目标格式 for (str_val in col3_cnt[sid]) { col3_str = col3_str (col3_str ? "," : "") col3_cnt[sid][str_val] "_" str_val } # 输出最终宽格式结果 print sid "\t" col2_str "\t" col3_str } } ' your_raw_data.txt
输出校验(匹配你给出的预期结果)
79264 3_Bacteria 3_Firmicutes 2947 7_Bacteria 6_Nitrospirae,1_Proteobacteria
注意:高版本gawk(4.0及以上)才支持二维数组结构,如果你使用的是低版本awk(比如macOS自带的默认awk),可以改用一维拼接结构实现,兼容性更强,逻辑完全一致:
awk ' { col2_cnt[$1 SUBSEP $2]++ col3_cnt[$1 SUBSEP $3]++ sample_list[$1] = 1 } END { for (sid in sample_list) { col2_str = ""; col3_str = "" # 匹配当前样本下所有第二列的计数记录 for (key in col2_cnt) { split(key, parts, SUBSEP) if (parts[1] == sid) { col2_str = col2_str (col2_str ? "," : "") col2_cnt[key] "_" parts[2] } } # 匹配当前样本下所有第三列的计数记录 for (key in col3_cnt) { split(key, parts, SUBSEP) if (parts[1] == sid) { col3_str = col3_str (col3_str ? "," : "") col3_cnt[key] "_" parts[2] } } print sid "\t" col2_str "\t" col3_str } } ' your_raw_data.txt
方案2:Python pandas 实现(适合后续需要做复杂数据清洗的场景)
如果数据量较大、后续还要开展多步分析,用pandas的分组聚合逻辑实现更简洁易维护:
import pandas as pd # 读取原始长格式数据 df = pd.read_csv("your_raw_data.txt", sep="\t", header=None, names=["sample", "col2", "col3"]) # 自定义拼接函数:按字符串值分组计数,生成目标格式的拼接结果 def format_cnt(series): cnt = series.value_counts() return ",".join([f"{v}_{k}" for k, v in cnt.items()]) # 按第一列分组,分别对第二、第三列做格式转换 result = df.groupby("sample").agg( col2=("col2", format_cnt), col3=("col3", format_cnt) ).reset_index() # 输出无表头的宽格式结果 result.to_csv("wide_format_result.txt", sep="\t", index=False, header=False)
内容的提问来源于stack exchange,提问作者guest33
相关产品推荐
相关产品推荐

