You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:19:16