Панды: точное совпадение строк с позицией между двумя кадрами данных - PullRequest
0 голосов
/ 09 июня 2018

Допустим, у меня есть два кадра данных ниже.

В действительности оба кадра данных будут иметь около миллиона строк каждый, поэтому я хотел бы найти наиболее эффективный способ сравнения:

  • каждого df2 ["BaseCall"] с каждымdf1 ["seq"]
  • возвращает фрейм данных, содержащий список позиций в каждом df1 ["gene"], где был найден любой df2 ["BaseCall"]

ОбщийЦель состоит в том, чтобы подсчитать, сколько раз каждый признак_функции был найден в гене, и захватить информацию о местоположении для использования в нисходящем направлении.

    # 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)

Вывод должен выглядеть примерно так:

|  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

Эта функция ngram, кажется, прекрасно работает, когда я использую только один тестовый базовый вызов на один seq, но у меня возникают проблемы с вычислениемнаиболее эффективный способ использования метода apply с одним аргументом из двух разных фреймов данных.Или, может быть, есть еще лучший способ найти подходящие строки / позиции между двумя кадрами данных?

 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

1 Ответ

0 голосов
/ 09 июня 2018

Учет возможных множественных вхождений одного и того же BaseCall в данном seq с использованием re.finditer() и некоторых взломов панд :

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]

Несколько BaseCall совпадений представлены в виде элементов списка в Position, но наш желаемый вывод помещает каждое совпадение в отдельную строку.Мы можем использовать apply(pd.Series), чтобы разбить столбец списков на несколько столбцов, а затем stack(), чтобы разбить столбцы на строки:

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

Мы можем groupby FeatureID и gene, чтобыполучить итоговые значения вхождения:

final.groupby(["FeatureID", "gene"]).Position.count()

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

Примечания: Для каждого вывода OP исключаются комбинации без совпадений.
Кроме того, при условии, что BaseCall - это только один столбец, а не оба Basecall и BaseCall отдельные столбцы.

...