Pandas:两个数据帧之间的精确字符串匹配,带位置
Pandas: exact string match, with position, between two dataframes
假设我有以下两个数据框。
实际上,两个数据帧各有大约一百万行,所以我想找到最有效的比较方法:
- 每个 df2["BaseCall"] 与每个 df1["seq"]
- return 包含每个 df1["gene"] 位置列表的数据框
发现任何 df2["BaseCall"] 的地方
总体目标是计算每个feature_id在基因中出现的次数,并捕获位置信息以供下游使用。
# 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 函数似乎工作得很好,但我无法找出最有效的方法来使用来自两个不同数据帧的一个参数的 apply 方法。或者也许有更好的方法来找到两个数据帧之间的匹配 strings/positions?
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
使用 re.finditer()
and :
计算给定 seq
中可能多次出现的相同 BaseCall
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
单独的列。
假设我有以下两个数据框。
实际上,两个数据帧各有大约一百万行,所以我想找到最有效的比较方法:
- 每个 df2["BaseCall"] 与每个 df1["seq"]
- return 包含每个 df1["gene"] 位置列表的数据框 发现任何 df2["BaseCall"] 的地方
总体目标是计算每个feature_id在基因中出现的次数,并捕获位置信息以供下游使用。
# 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 函数似乎工作得很好,但我无法找出最有效的方法来使用来自两个不同数据帧的一个参数的 apply 方法。或者也许有更好的方法来找到两个数据帧之间的匹配 strings/positions?
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
使用 re.finditer()
and
seq
中可能多次出现的相同 BaseCall
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
单独的列。