[英]Fast way to convert strings into lists of ints in a Pandas column?
我正在嘗試計算大型數據幀中列中所有字符串之間的漢明距離。 我在此列中有超過100,000行,因此所有成對組合都是10x10 ^ 9比較。 這些串是短DNA序列。 我想快速將列中的每個字符串轉換為整數列表,其中唯一的整數表示字符串中的每個字符。 例如
"ACGTACA" -> [0, 1, 2, 3, 1, 2, 1]
然后我使用scipy.spatial.distance.pdist
快速有效地計算所有這些之間的漢明距離。 在熊貓中有快速的方法嗎?
我嘗試過使用apply
但速度很慢:
mapping = {"A":0, "C":1, "G":2, "T":3}
df.apply(lambda x: np.array([mapping[char] for char in x]))
get_dummies
和其他分類操作不適用,因為它們在每行級別上運行。 不在行內。
由於漢明距離並不關心幅度差異,因此我可以用df.apply(lambda x: np.array([mapping[char] for char in x]))
替換df.apply(lambda x: np.array([mapping[char] for char in x]))
來獲得大約40-60%的加速df.apply(lambda x: map(ord, x))
在虛構數據集上。
我沒有測試它的性能,但你也可以嘗試類似的東西
atest = "ACGTACA"
alist = atest.replace('A', '3.').replace('C', '2.').replace('G', '1.').replace('T', '0.').split('.')
anumlist = [int(x) for x in alist if x.isdigit()]
結果是:
[3, 2, 1, 0, 3, 2, 3]
編輯:好的,所以用atest =“ACTACA”測試它* 100000需要一段時間:/也許不是最好的主意......
編輯5:另一項改進:
import datetime
import numpy as np
class Test(object):
def __init__(self):
self.mapping = {'A' : 0, 'C' : 1, 'G' : 2, 'T' : 3}
def char2num(self, astring):
return [self.mapping[c] for c in astring]
def main():
now = datetime.datetime.now()
atest = "AGTCAGTCATG"*10000000
t = Test()
alist = t.char2num(atest)
testme = np.array(alist)
print testme, len(testme)
print datetime.datetime.now() - now
if __name__ == "__main__":
main()
對於110.000.000個字符大約需要16秒,並且讓處理器忙碌而不是你的ram:
[0 2 3 ..., 0 3 2] 110000000
0:00:16.866659
創建測試數據
In [39]: pd.options.display.max_rows=12
In [40]: N = 100000
In [41]: chars = np.array(list('ABCDEF'))
In [42]: s = pd.Series(np.random.choice(chars, size=4 * np.prod(N)).view('S4'))
In [45]: s
Out[45]:
0 BEBC
1 BEEC
2 FEFA
3 BBDA
4 CCBB
5 CABE
...
99994 EEBC
99995 FFBD
99996 ACFB
99997 FDBE
99998 BDAB
99999 CCFD
dtype: object
這些實際上不必與我們這樣做的長度相同。
In [43]: maxlen = s.str.len().max()
In [44]: result = pd.concat([ s.str[i].astype('category',categories=chars).cat.codes for i in range(maxlen) ], axis=1)
In [47]: result
Out[47]:
0 1 2 3
0 1 4 1 2
1 1 4 4 2
2 5 4 5 0
3 1 1 3 0
4 2 2 1 1
5 2 0 1 4
... .. .. .. ..
99994 4 4 1 2
99995 5 5 1 3
99996 0 2 5 1
99997 5 3 1 4
99998 1 3 0 1
99999 2 2 5 3
[100000 rows x 4 columns]
因此,您可以根據相同的類別進行分解(例如,代碼是有意義的)
並且非常快
In [46]: %timeit pd.concat([ s.str[i].astype('category',categories=chars).cat.codes for i in range(maxlen) ], axis=1)
10 loops, best of 3: 118 ms per loop
使用ord
或基於字典的查找確切地映射A-> 0,C-> 1等似乎沒有太大區別:
import pandas as pd
import numpy as np
bases = ['A', 'C', 'T', 'G']
rowlen = 4
nrows = 1000000
dna = pd.Series(np.random.choice(bases, nrows * rowlen).view('S%i' % rowlen))
lookup = dict(zip(bases, range(4)))
%timeit dna.apply(lambda row: map(lookup.get, row))
# 1 loops, best of 3: 785 ms per loop
%timeit dna.apply(lambda row: map(ord, row))
# 1 loops, best of 3: 713 ms per loop
Jeff的解決方案在性能方面也差不多:
%timeit pd.concat([dna.str[i].astype('category', categories=bases).cat.codes for i in range(rowlen)], axis=1)
# 1 loops, best of 3: 1.03 s per loop
這種方法相對於將行映射到整數列表的一個主要優點是,可以通過.values
屬性將類別視為單個(nrows, rowlen)
uint8數組,然后可以將其直接傳遞給pdist
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.