如何在熊猫中使用具有多索引的地图?

Posted

技术标签:

【中文标题】如何在熊猫中使用具有多索引的地图?【英文标题】:How can I use map with multi-index in pandas? 【发布时间】:2017-08-22 00:13:46 【问题描述】:

我有一个包含各种基因组位置的数据表。这些位置表示为 3 元组('chromosome'、'srand'、位置),我已将其转换为多索引。我的目标是查找有关每个位置的各种信息并将其添加到表格中(例如基因名称等)。我可以使用 pybedtools 来做到这一点。

df = pd.DataFrame(data='A':range(1,8), 'B':range(1,8), 'C': range(1,8),
 index=pd.MultiIndex.from_tuples([('chrom1', '-', 1234), ('chrom1', '+', 5678),
 ('chrom1', '+', 9876),  ('chrom2', '+', 13579), ('chrom2', '+', 8497), ('chrom2', '-', 98765),
 ('chrom2', '-', 76856)]))

df.index.rename(['chrom','strand','abs_pos'], inplace=True)

                       A  B  C
chrom  strand abs_pos         
chrom1 -      1234     1  1  1
       +      5678     2  2  2
              9876     3  3  3
chrom2 +      13579    4  4  4
              8497     5  5  5
       -      98765    6  6  6
              76856    7  7  7

我的问题是将列添加到具有多索引的数据框中。如果没有多索引,这似乎很简单:pandas - add new column to dataframe from dictionary

我有一个查找信息的字典,其中包含与多索引相对应的三元组键。如何将此数据添加为新列?

gene_d = ('chrom1', '-', 1234) : 'geneA', ('chrom1', '+', 5678): 'geneB', 
    ('chrom1', '+', 9876): 'geneC', ('chrom2', '+', 13579): 'geneD',
    ('chrom2', '+', 8497): 'geneE', ('chrom2', '-', 98765): 'geneF', 
    ('chrom2', '-', 76856): 'geneG'

我已经尝试过 map,但似乎无法弄清楚如何让它与多索引一起使用以产生以下结果:

                                A  B  C
chrom  strand abs_pos gene
chrom1 -      1234    geneA     1  1  1
       +      5678    geneB     2  2  2
              9876    geneC     3  3  3
chrom2 +      13579   geneD     4  4  4
              8497    geneE     5  5  5
       -      98765   geneF     6  6  6
              76856   geneG     7  7  7

【问题讨论】:

【参考方案1】:

矢量化方法:

df['gene'] = df.index #you get the index as tuple
df['gene'] = df['gene'].map(gene_d)
df = df.set_index('gene', append=True)

结果df:

                                A   B   C
chrom   strand  abs_pos gene            
chrom1  -       1234    geneA   1   1   1
        +       5678    geneB   2   2   2
                9876    geneC   3   3   3
chrom2  +       13579   geneD   4   4   4
                8497    geneE   5   5   5
        -       98765   geneF   6   6   6
                76856   geneG   7   7   7

【讨论】:

【参考方案2】:

将gene_d制作成数据框:

df1 = pd.DataFrame.from_dict(gene_d, orient='index').rename(columns=0:'gene')

给它一个多重索引:

df1.index = pd.MultiIndex.from_tuples(df1.index)

与原始df连接:

new_df = pd.concat([df, df1], axis=1).sort_values('A')

做一些清理工作:

new_df.index.rename(['chrom','strand','abs_pos'], inplace=True)
new_df.set_index('gene', append=True)
new_df

                             A  B  C
chrom  strand abs_pos gene          
chrom1 -      1234    geneA  1  1  1
       +      5678    geneB  2  2  2
              9876    geneC  3  3  3
chrom2 +      13579   geneD  4  4  4
              8497    geneE  5  5  5
       -      98765   geneF  6  6  6
              76856   geneG  7  7  7

【讨论】:

【参考方案3】:

一种非矢量化的方法,但可能对真正为此苦苦挣扎的人有用。

在我的示例中,我有一个名为 bb_df 的 df,它有一个以 [customer, months] 为结构的多索引,每个站点下面都有多个月。多重索引的结构类似于 (levels = [level_1, level_2], labels = [level_1, level_2])。因此,您可以按顺序获取 2 级的完整列表,以便通过以下列表理解进行映射:

[bb_df.index.levels[1][x] for x in bb_df.index.labels[1]]

希望这对某人有所帮助。

【讨论】:

【参考方案4】:

我遇到了类似的问题,发现使用地图并不简单。相反,我不得不使用for loop 重写我的代码以获得预期的答案。

它不像使用 map 那样干净,但是通过键分配每个键可以避免不必要地添加其他持有数据帧,并解释字典中的缺失值,比如 ('chrom1', '+', 9876) 是否已经有一个你没有的值想换。


    df['gene'] = '' # Add a column for replacement strings if not present
    # Create a for-loop that cycles through keys and values
    for gnk, gnv in gene_d.items(): df.loc[gnk, 'gene'] = gnv
    df.set_index('gene', append=True, inplace=True)

我知道,就速度而言,这可能不是最好的,但我也没有针对更大的数据集进行测试。

这是我遇到的问题的代码和输出(gene_make() 只是在df 中读取问题状态):


    gene_test = ('chrom1', '+', 9876): 'geneQ', ('chrom2', '+', 13579): 'geneP'
    gene_d = ('chrom1', '-', 1234) : 'geneA', ('chrom1', '+', 5678): 'geneB', 
    #     ('chrom1', '+', 9876): 'geneC', ('chrom2', '+', 13579): 'geneD',
        ('chrom2', '+', 8497): 'geneE', ('chrom2', '-', 98765): 'geneF', 
        ('chrom2', '-', 76856): 'geneG'

    df = gene_make()
    df['gene'] = np.nan
    for gnk, gnv in gene_test.items(): df.loc[gnk, 'gene'] = gnv
    df.set_index('gene', append=True, inplace=True)
    display(df)
    
    df = gene_make()
    df['gene'] = df.index
    for gnk, gnv in gene_test.items(): df.loc[gnk, 'gene'] = gnv
    df['gene'] = df['gene'].map(gene_d)
    df = df.set_index('gene', append=True)
    display(df)

输出:

                             A  B  C
chrom  strand abs_pos gene          
chrom1 -      1234    NaN    1  1  1
       +      5678    NaN    2  2  2
              9876    geneQ  3  3  3
chrom2 +      13579   geneP  4  4  4
              8497    NaN    5  5  5
       -      98765   NaN    6  6  6
              76856   NaN    7  7  7

                             A  B  C
chrom  strand abs_pos gene          
chrom1 -      1234    geneA  1  1  1
       +      5678    geneB  2  2  2
              9876    NaN    3  3  3
chrom2 +      13579   NaN    4  4  4
              8497    geneE  5  5  5
       -      98765   geneF  6  6  6
              76856   geneG  7  7  7

当然,更改 for-loopmap 的顺序可能有助于解决此问题。

    
    df = gene_make()
    df['gene'] = df.index
    df['gene'] = df['gene'].map(gene_d)
    for gnk, gnv in gene_test.items(): df.loc[gnk, 'gene'] = gnv
    df.set_index('gene', append=True, inplace=True)
    display(df)

输出:

                             A  B  C
chrom  strand abs_pos gene          
chrom1 -      1234    geneA  1  1  1
       +      5678    geneB  2  2  2
              9876    geneQ  3  3  3
chrom2 +      13579   geneP  4  4  4
              8497    geneE  5  5  5
       -      98765   geneF  6  6  6
              76856   geneG  7  7  7

【讨论】:

以上是关于如何在熊猫中使用具有多索引的地图?的主要内容,如果未能解决你的问题,请参考以下文章

具有可迭代对象的字典字典到具有多索引的可迭代对象索引的熊猫数据框

如何在不合并索引的情况下连接具有不同多索引的两个数据帧?

如何计算熊猫中重新采样的多索引数据帧

如何在熊猫中获得多级 x 轴标记图?

在熊猫数据框上设置多索引的最佳方法

切片具有大列表的多索引熊猫数据框