首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Pandas:两个数据帧之间的精确字符串匹配,带位置

Pandas:两个数据帧之间的精确字符串匹配,带位置
EN

Stack Overflow用户
提问于 2018-06-09 05:44:09
回答 1查看 1.3K关注 0票数 1

假设我有下面两个数据帧。

实际上,这两个数据帧都有大约一百万行,所以我想找出最有效的比较方法:

  • 每个df2"BaseCall“和每个df1"seq”
  • 返回一个数据帧,其中包含在每个df1“df2”上发现任何BaseCall“BaseCall”的位置列表

总体目标是计算在基因中发现每个feature_id的次数,并捕获位置信息以供下游使用。

代码语言:javascript
复制
    # break fasta_df sequences and mutation seqs up into kmers
    data = [{"gene":"pik3ca", "start":"179148724", "stop":"179148949","seq":"TTTGCTTTATCTTTTGTTTTTGCTTTAGCTGAAGTATTTTAAAGTCAGTTACAG"},
    {"gene":"brca1", "start":"179148724", "stop":"179148949","seq":"CAATATCTACCATTTGTTAACTTTGTTCTATTATCATAACTACCAAAATTAACAGA"},
    {"gene":"kras1", "start":"179148724", "stop":"179148949","seq":"AAAACCCAGTAGATTTTCAAATTTTCCCAACTCTTCCACCAATGTCTTTTTACATCT"}] 

    # test dataframe with input seq    
    df1 = pd.DataFrame(data)

    data2 = [{"FeatureID":"1_1_15", "BaseCall":"TTTGTT"},
         {"FeatureID":"1_1_15", "BaseCall":"AATATC"},
         {"FeatureID":"1_1_16", "BaseCall":"GTTTTT"},
         {"FeatureID":"1_1_16", "BaseCall":"GTTCTA"},
         ]

    df2= pd.DataFrame(data2)

输出应如下所示:

代码语言:javascript
复制
|  gene  |   feature_id   |   BaseCall   |   Position 
| pik3ca |   1_1_15       |   TTTGTT     |    12
| pik3ca |   1_1_16       |   GTTTTT     |    15
| brca1  |   1_1_16       |   GTTCTA     |    24
| brca1  |   1_1_15       |   AATATC     |    1
| brca1  |   1_1_15       |   TTTGTT     |    12
| brca1  |   1_1_15       |   TTTGTT     |    21

当我在一个seq上只使用一个test basecall时,这个ngram函数似乎工作得很好,但我找不出最有效的方法来使用apply方法,其中一个参数来自两个不同的数据帧。或者,也许有一种更好的方法来查找两个数据帧之间的匹配字符串/位置?

代码语言:javascript
复制
 def ngrams(string, target):
    ngrams = zip(*[string[i:] for i in range(6)])
    output = [''.join(ngram)for ngram in ngrams]
    indices = [(i,x) for i, x in enumerate(output) if x == target]
    return indices
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-06-09 07:03:36

使用re.finditer()some Pandas hacking解决同一BaseCall在给定seq中可能多次出现的问题

代码语言:javascript
复制
import re

def match_basecall(pattern, string):
    match = re.finditer(pattern, string)
    start_pos = [m.start() for m in match]
    if not start_pos:
        return None
    return start_pos

matches = df2.BaseCall.apply(lambda bc: df1.seq.apply(lambda x: match_basecall(bc, x)))
matches.columns = df1.gene

merged = matches.merge(df2, left_index=True, right_index=True)

melted = merged.melt(id_vars=["FeatureID", "BaseCall"], 
                     var_name="gene", 
                     value_name="Position").dropna()

melted
  FeatureID BaseCall    gene  Position
0    1_1_15   TTTGTT  pik3ca      [12]
2    1_1_16   GTTTTT  pik3ca      [15]
4    1_1_15   TTTGTT   brca1  [12, 21]
5    1_1_15   AATATC   brca1       [1]
7    1_1_16   GTTCTA   brca1      [24]

Position中,多个BaseCall匹配项被表示为列表项,但是我们所需的输出将每个匹配项放在单独的行中。我们可以使用apply(pd.Series)将一列列表分解为多列,然后使用stack()将列转换为行:

代码语言:javascript
复制
stacked = (pd.DataFrame(melted.Position.apply(pd.Series).stack())
             .reset_index(level=1, drop=True)
             .rename(columns={0:"Position"}))

final = melted.drop("Position", 1).merge(stacked, left_index=True, right_index=True)

final
  FeatureID BaseCall    gene  Position
0    1_1_15   TTTGTT  pik3ca      12.0
2    1_1_16   GTTTTT  pik3ca      15.0
4    1_1_15   TTTGTT   brca1      12.0
4    1_1_15   TTTGTT   brca1      21.0
5    1_1_15   AATATC   brca1       1.0
7    1_1_16   GTTCTA   brca1      24.0

我们可以对FeatureIDgene执行groupby命令,以获得出现次数的总数:

代码语言:javascript
复制
final.groupby(["FeatureID", "gene"]).Position.count()

FeatureID  gene  
1_1_15     brca1     3
           pik3ca    1
1_1_16     brca1     1
           pik3ca    1

注意:对于每个OP输出,没有匹配的组合将被排除。

另外,这里假设BaseCall只有一列,并且没有BasecallBaseCall两个单独的列。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50768765

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档