在多个条件下合并DataFrame - 特别是在相等的值上

Tim*_*ths 7 python merge pandas pandasql

首先,对不起,如果这有点长,但我想完整地描述我遇到的问题以及我已经尝试过的问题.

我试图在多个条件下将两个数据帧对象连接(合并)在一起.如果要满足的条件都是"等于"运算符,我知道如何做到这一点,但是,我需要使用的不仅仅是更多.

数据框代表遗传信息:一个是基因组中的突变列表(称为SNP),另一个是基因在人类基因组上的位置信息.对它们执行df.head()会返回以下内容:

SNP DataFrame(snp_df):

   chromosome        SNP      BP
0           1  rs3094315  752566
1           1  rs3131972  752721
2           1  rs2073814  753474
3           1  rs3115859  754503
4           1  rs3131956  758144
Run Code Online (Sandbox Code Playgroud)

这显示了SNP参考ID及其位置.'BP'代表'Base-Pair'位置.

Gene DataFrame(gene_df):

   chromosome  chr_start  chr_stop        feature_id
0           1      10954     11507  GeneID:100506145
1           1      12190     13639  GeneID:100652771
2           1      14362     29370     GeneID:653635
3           1      30366     30503  GeneID:100302278
4           1      34611     36081     GeneID:645520
Run Code Online (Sandbox Code Playgroud)

该数据框显示了所有感兴趣的基因的位置.

我想知道的是所有属于基因组中基因区域的SNP,并丢弃那些在这些区域之外的SNP.

如果我想基于多个(等于)条件将两个数据帧合并在一起,我会做类似以下的事情:

merged_df = pd.merge(snp_df, gene_df, on=['chromosome', 'other_columns'])
Run Code Online (Sandbox Code Playgroud)

然而,在这种情况下 - 我需要找到染色体值与Gene数据帧中的那些匹配的SNP,并且BP值落在'chr_start'和'chr_stop'之间.这种挑战的原因是这些数据帧非常大.在此当前数据集中,snp_df具有6795021行,并且gene_df具有34362.

我试图通过分别观察染色体或基因来解决这个问题.由于未使用性染色体,因此有22种不同的染色体值(第1-22位).这两种方法都耗费了很长时间.一个使用该pandasql模块,而另一个方法是循环通过单独的基因.

SQL方法

import pandas as pd
import pandasql as psql

pysqldf = lambda q: psql.sqldf(q, globals())

q           = """
SELECT s.SNP, g.feature_id
FROM this_snp s INNER JOIN this_genes g
WHERE s.BP >= g.chr_start
AND s.BP <= g.chr_stop;
"""

all_dfs = []

for chromosome in snp_df['chromosome'].unique():
    this_snp    = snp_df.loc[snp_df['chromosome'] == chromosome]
    this_genes  = gene_df.loc[gene_df['chromosome'] == chromosome]
    genic_snps  = pysqldf(q)
    all_dfs.append(genic_snps)

all_genic_snps  = pd.concat(all_dfs)
Run Code Online (Sandbox Code Playgroud)

基因迭代法

all_dfs = []
for line in gene_df.iterrows():
    info    = line[1] # Getting the Series object
    this_snp = snp_df.loc[(snp_df['chromosome'] == info['chromosome']) &
            (snp_df['BP'] >= info['chr_start']) & (snp_df['BP'] <= info['chr_stop'])]
    if this_snp.shape[0] != 0:
        this_snp = this_snp[['SNP']]
        this_snp.insert(len(this_snp.columns), 'feature_id', info['feature_id'])
        all_dfs.append(this_snp)


all_genic_snps = pd.concat(all_dfs)
Run Code Online (Sandbox Code Playgroud)

任何人都可以提出更有效的方法吗?

kha*_*mel 1

您可以使用以下内容来完成您正在寻找的内容:

merged_df=snp_df.merge(gene_df,on=['chromosome'],how='inner')
merged_df=merged_df[(merged_df.BP>=merged_df.chr_start) & (merged_df.BP<=merged_df.chr_stop)][['SNP','feature_id']]
Run Code Online (Sandbox Code Playgroud)

注意:您的示例数据帧不符合您的加入标准。这是使用修改后的数据帧的示例:

snp_df
Out[193]: 
   chromosome        SNP      BP
0           1  rs3094315  752566
1           1  rs3131972   30400
2           1  rs2073814  753474
3           1  rs3115859  754503
4           1  rs3131956  758144

gene_df
Out[194]: 
   chromosome  chr_start  chr_stop        feature_id
0           1      10954     11507  GeneID:100506145
1           1      12190     13639  GeneID:100652771
2           1      14362     29370     GeneID:653635
3           1      30366     30503  GeneID:100302278
4           1      34611     36081     GeneID:645520

merged_df
Out[195]: 
         SNP        feature_id
8  rs3131972  GeneID:100302278
Run Code Online (Sandbox Code Playgroud)

  • 我确实考虑过使用这种方法 - 问题是对完整数据帧的合并操作会产生巨大的输出。如果我举个例子——仅对于 1 号染色体,gene_df 中有 3511 个条目,snp_df 中有 528381 个条目。因此,仅此染色体上的内连接就会产生 1855145691 个条目!另外,我在原始问题中显示的数据帧只是 head() 方法的结果。因此,虽然那里没有任何匹配项,但完整数据框中应该有很多匹配项。 (2认同)