Найдите разницу между строками для каждых двух строк pandas data.frame - PullRequest
4 голосов
/ 12 апреля 2020

Я новичок в python, и я борюсь с этим в течение некоторого времени. У меня есть файл, который выглядит так:

    name   seq
1   a1     bbb
2   a2     bbc
3   b1     fff
4   b2     fff
5   c1     aaa
6   c2     acg

, где name - это имя строки, а seq - строка. Я хотел бы новый столбец или новый фрейм данных, который указывает количество различий между каждыми двумя строками без перекрытия. Например, я хочу количество различий между последовательностями для имени [a1-a2], затем [b1-b2] и, наконец, между [c1-c2].

Так что мне нужно что-то вроде этого:

    name   seq   diff  
1   a1     bbb    NA   
2   a2     bbc    1
3   b1     fff    NA
4   b2     fff    0
5   c1     aaa    NA
6   c2     acg    2

Любая помощь высоко ценится

Ответы [ 4 ]

5 голосов
/ 12 апреля 2020

Похоже, вы хотите расстояние jaccard пар строк. Вот один из способов использования groupby и scipy.spatial.distance.jaccard:

from scipy.spatial.distance import jaccard
g = df.groupby(df.name.str[0])

df['diff'] = [sim for _, seqs in g.seq for sim in 
              [float('nan'), jaccard(*map(list,seqs))]]

print(df)

  name  seq  diff
1   a1  bbb   NaN
2   a2  bbc   1.0
3   b1  fff   NaN
4   b2  fff   0.0
5   c1  aaa   NaN
6   c2  acg   2.0
4 голосов
/ 12 апреля 2020

Альтернатива с Levenshtein расстоянием:

import Levenshtein
s = df['name'].str[0]
out = df.assign(Diff=s.drop_duplicates(keep='last').map(df.groupby(s)['seq']
                    .apply(lambda x: Levenshtein.distance(x.iloc[0],x.iloc[-1]))))

  name  seq  Diff
1   a1  bbb   NaN
2   a2  bbc   1.0
3   b1  fff   NaN
4   b2  fff   0.0
5   c1  aaa   NaN
6   c2  acg   2.0
1 голос
/ 12 апреля 2020

В качестве первого шага я воссоздаю ваши данные с помощью:

#!/usr/bin/env python3
import pandas as pd

# Setup
data = {'name': {1: 'a1', 2: 'a2', 3: 'b1', 4: 'b2', 5: 'c1', 6: 'c2'}, 'seq': {1: 'bbb', 2: 'bbc', 3: 'fff', 4: 'fff', 5: 'aaa', 6: 'acg'}}
df = pd.DataFrame(data)

Решение Вы можете попробовать перебрать кадр данных и сравнить значение seq последней итерации с текущий. Для сравнения двух строк (хранящихся в столбцах seq вашего информационного кадра) вы можете применить простое понимание списка, как в этой функции:

def diff_letters(a,b):
    return sum ( a[i] != b[i] for i in range(len(a)) )

Итерация по строкам Dataframe

diff = ['NA']

row_iterator = df.iterrows()
_, last = next(row_iterator)

# Iterate over the df get populate a list with result of the comparison
for i, row in row_iterator:
    if i % 2 == 0:
        diff.append(diff_letters(last['seq'],row['seq']))
    else:
        # for odd row numbers append NA value
        diff.append("NA")
    last = row
df['diff'] = diff

Результат выглядит так

  name  seq diff
1   a1  bbb   NA
2   a2  bbc    1
3   b1  fff   NA
4   b2  fff    0
5   c1  aaa   NA
6   c2  acg    2
0 голосов
/ 12 апреля 2020

Отметьте это

import pandas as pd

data = {'name':  ['a1', 'a2','b1','b2','c1','c2'],
    'seq': ['bbb', 'bbc','fff','fff','aaa','acg']
    }

df = pd.DataFrame (data, columns = ['name','seq'])
diffCntr=0
df['diff'] = np.nan
i=0
while i < len(df)-1:
    diffCntr=np.nan
    item=df.at[i,'seq']
    df.at[i,'diff']=diffCntr
    diffCntr=0
    for j in df.at[i+1,'seq']:
        if item.find(j) < 0:
            diffCntr +=1
    df.at[i+1,'diff']=diffCntr
    i +=2    
df  

Результат будет таким:

    name seq    diff
0   a1   bbb    NaN
1   a2   bbc    1.0
2   b1   fff    NaN
3   b2   fff    0.0
4   c1   aaa    NaN
5   c2   acg    2.0
...