【问题标题】:Calculating and placing values into a second level column in a MultiIndex Pandas DataFrame计算并将值放入 M​​ultiIndex Pandas DataFrame 中的第二级列
【发布时间】:2017-09-05 23:20:35
【问题描述】:

我有一个多索引 DataFrame,我想在其中放置一个名为 AB 的二级列。此第二级列的值应等于每个样本的 AD[1]/DP,例如样品1 AB = 60/180

import pandas as pd
import numpy as np

genotype_data = [
                    ['0/1', '120,60', 180, 5, '0/1', '200,2', 202, 99],
                    ['0/1', '200,20', 60, 99, '0/1', '200,50', 250, 99],
                    ['0/1', '200,2', 202, 99, '0/1', '200,2', 202, 99] 
]


genotype_columns = [['Sample1', 'Sample2'], ['GT', 'AD', 'DP', 'GQ']]
cols = pd.MultiIndex.from_product(genotype_columns)
df = pd.DataFrame(data=genotype_data, columns=cols)

此代码生成以下输入文件/df:

   Sample1                        Sample2                       
GT      AD   DP  GQ      GT      AD   DP  GQ
0/1  120,60  180   5     0/1   200,2  202  99
0/1  200,20   60   3     0/1  200,50  250  99
0/1   200,2  202  99     0/1   200,2  202  99

期望的结果应该是:

      Sample1                        Sample2                       
GT      AD   DP  GQ    AB      GT      AD   DP  GQ    AB
0/1  120,60  180   5  0.33     0/1   200,2  202  99  0.01
0/1  200,20   60   3  0.33     0/1  200,50  250  99  0.20
0/1   200,2  202  99  0.01     0/1   200,2  202  99  0.01

我已经想出了一个解决方案,但它非常缓慢、低效并且依赖于循环。我需要一个更有效的解决方案,因为我将在非常大的文件上执行此操作。

def calc_AB(df):

    sam = df.columns.levels[0][0]
    AD = df.xs('AD', level=1, axis=1).unstack().str.split(",", n=2)
    DP = df.xs('DP', level=1, axis=1).unstack()
    AB = round(pd.to_numeric(AD.str[1]) / pd.to_numeric(DP), 2)
    df[sam, 'AB'] = AB.tolist()

    return df 


dfs = [calc_AB(df[[sam]].astype(str)) for sam in df.columns.levels[0].tolist()]

pd.concat(dfs, axis=1) 

对此的任何帮助将不胜感激。

【问题讨论】:

    标签: python pandas dataframe data-manipulation multi-index


    【解决方案1】:

    您需要重新组织索引以确保只有一列称为“AD”:

    df.columns = df.columns.swaplevel(0,1)
    stacked = df.stack()
    #               AD   DP  GQ   GT    
    #0 Sample1  120,60  180   5  0/1  
    #  Sample2   200,2  202  99  0/1 
    #1 Sample1  200,20   60  99  0/1 
    #  Sample2  200,50  250  99  0/1 
    #2 Sample1   200,2  202  99  0/1 
    #  Sample2   200,2  202  99  0/1 
    

    现在计算新列很简单:

    stacked['AB'] = stacked['AD'].str.split(',').str[1].astype(int)/stacked['DP']
    
    stacked
    #               AD   DP  GQ   GT        AB
    #0 Sample1  120,60  180   5  0/1  0.333333
    #  Sample2   200,2  202  99  0/1  0.009901
    #1 Sample1  200,20   60  99  0/1  0.333333
    #  Sample2  200,50  250  99  0/1  0.200000
    #2 Sample1   200,2  202  99  0/1  0.009901
    #  Sample2   200,2  202  99  0/1  0.009901
    

    如果需要,您可以将索引恢复到之前的任何状态。

    【讨论】:

    • 我喜欢 stack() 的这种用法... 并且 unstack df = stacked.stack().unstack([1,-1]).sort_index()
    • 令人惊讶/不幸的是,这需要与我的解决方案相同的时间来处理。但是,它更干净,更好,所以我现在就使用它。
    • 在对不同的大文件进行进一步测试后,我发现它实际上比我的解决方案慢了约 8 倍。
    猜你喜欢
    • 2022-07-06
    • 2020-05-13
    • 1970-01-01
    • 1970-01-01
    • 2014-12-03
    • 2021-01-06
    • 2021-04-16
    • 1970-01-01
    相关资源
    最近更新 更多