Pandas:如何将子集函数处理结果合并回原始DataFrame
解决分位数归一化后的值合并回原始DataFrame的问题
嘿,我也是从Pandas新手阶段摸爬滚打过来的,完全理解你想把处理后的数据无缝合并回原表的需求!咱们一步步来搞定这个问题:
1. 先重现你的前期操作(确保对齐你的流程)
首先,先把你的数据和筛选、转格式、归一化的步骤复现出来,方便后续衔接:
import pandas as pd import numpy as np # 你的原始数据 df = pd.DataFrame({ 'gene': ['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd', 'e', 'e', 'e', 'f', 'f', 'f'], 'rep': [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3], 'val': [5, 4, 3, 2, 1, 4, 3, 4, 6, 4, 2, 8, 0, 1, 0, 0, 2, 4], 'subset':['y', 'y', 'y', 'y', 'y', 'y', 'y', 'y', 'y', 'y', 'y', 'y', 'n', 'n', 'n', 'n', 'n', 'n'] }) # 筛选subset='y'的子数据集 df_y = df[df['subset'] == 'y'] # 转成宽格式(gene为行,rep为列) df_y_wide = df_y.pivot(index='gene', columns='rep', values='val') # 定义分位数归一化函数(参考维基百科的逻辑) def quantile_normalize(df): # 对所有元素排名 ranks = df.stack().rank(method='min').unstack() # 获取排序后的所有值 sorted_vals = df.stack().sort_values().values # 计算每个分位数的均值 mean_vals = sorted_vals.reshape(df.shape).mean(axis=1) # 根据排名映射到均值 return ranks.apply(lambda x: mean_vals[x-1].tolist()) # 执行归一化 df_y_normalized = quantile_normalize(df_y_wide)
2. 方法一:转长格式后用Merge合并
这是最直观的方法,把归一化后的宽表转成和原始df一致的扁平化结构,再通过merge匹配合并:
# 把归一化后的宽表转成长格式 df_y_normalized_long = df_y_normalized.unstack().reset_index(name='normalized_val') # 调整列名顺序,和原始df的gene、rep对应 df_y_normalized_long = df_y_normalized_long[['gene', 'rep', 'normalized_val']] # 合并回原始DataFrame,用left join保留所有原始行 df_merged = df.merge(df_y_normalized_long, on=['gene', 'rep'], how='left') # 对于subset='n'的行,可以选择保留原val或设为NaN(这里选择保留原val) df_merged['normalized_val'] = df_merged.apply( lambda row: row['val'] if row['subset'] == 'n' else row['normalized_val'], axis=1 )
3. 方法二:用字典映射快速赋值
如果觉得转格式麻烦,可以直接把归一化结果转成字典,用元组(gene, rep)作为键,直接给原始df赋值:
# 把归一化后的宽表转成字典,键为(rep, gene),所以需要调整顺序为(gene, rep) norm_dict = df_y_normalized.unstack().to_dict() norm_dict = {(gene, rep): val for (rep, gene), val in norm_dict.items()} # 给原始df新增归一化列,subset='y'的行取字典值,'n'的行保留原val df['normalized_val'] = df.apply( lambda row: norm_dict.get((row['gene'], row['rep']), row['val']), axis=1 )
两种方法最终都会得到一个包含原始所有数据,且subset='y'的行带有归一化后值的DataFrame,完全匹配你的原始数据结构~
内容的提问来源于stack exchange,提问作者SumNeuron
相关产品推荐
相关产品推荐

