我已经有一段时间没有这个问题了,我认为这与我对如何使用combineByKey和reduceByKey缺乏了解有关,所以希望有人可以解决这个问题。
我正在处理DNA序列,所以我有一个程序来产生一堆不同版本的(前向,后向和称赞)。我有几个阅读框,这意味着对于字符串ABCABC
,我想要以下一系列密钥:ABC ABC
,A BCA BC
,AB CAB C
。
现在我使用以下函数来解决问题(我在flatMap程序中运行):
# Modified from http://stackoverflow.com/questions/312443/how-do-you-split-a-list-into-evenly-sized-chunks-in-python
def chunkCodons((seq, strand, reading_frame)):
"""
Yield successive codons from seq
"""
# Get the first characters
if reading_frame > 0:
yield (0, seq[0:reading_frame], strand, reading_frame)
for i in xrange(reading_frame, len(seq), 3):
if i % 1000000 == 0:
print "Base # = {:,}".format(i)
yield (i, seq[i:i + 3], strand, reading_frame)
我这样运行:reading_frames_rdd = nascent_reading_frames_rdd.flatMap(chunkCodons)
然而,这需要很长时间才能获得长串的DNA,所以我知道这一定是错的。
因此,我想让Spark以更直接的方式做到这一点,方法是通过字符(即基数)将其分解,然后一次重新组合3。问题是我必须组合不同的键,但相邻。这意味着,如果我有(1, 'A'), (2, 'B'), (3, 'C'),....
,我希望能够生成(1,' ABC')。
我不知道该怎么做。我怀疑我需要使用combineByKey并让它只有条件地产生输出。我是否只是让它产生的输出可以被combineByKey消耗,如果它符合我的条件?那是我应该怎么做的?
修改:
以下是我的输入:[(0, 'A'), (1, 'A'), (2, 'B'), (3, 'A'), (4, 'C'), ....]
我想要这样的输出:[(0, 0, 'AAB'), (0, 1, 'ABX'), ...]
和[(1, 0, 'A'), (1, 1, 'ABA'), (1, 2, 'CXX')...]
。
格式为[(reading frame, first base #, sequence)]
答案 0 :(得分:2)
您可以尝试这样的事情:
seq = sc.parallelize(zip(xrange(16), "ATCGATGCATGCATGC"))
(seq
.flatMap(lambda (pos, x): ((pos - i, (pos, x)) for i in range(3)))
.groupByKey()
.mapValues(lambda x: ''.join(v for (pos, v) in sorted(x)))
.filter(lambda (pos, codon): len(codon) == 3)
.map(lambda (pos, codon): (pos % 3, pos, codon))
.collect())
和结果:
[(0, 0, 'ATC'),
(1, 1, 'TCG'),
(2, 2, 'CGA'),
(0, 3, 'GAT'),
(1, 4, 'ATG'),
(2, 5, 'TGC'),
(0, 6, 'GCA'),
(1, 7, 'CAT'),
(2, 8, 'ATG'),
(0, 9, 'TGC'),
(1, 10, 'GCA'),
(2, 11, 'CAT'),
(0, 12, 'ATG'),
(1, 13, 'TGC')]
在实践中,我会尝试别的东西:
from toolz.itertoolz import sliding_window, iterate, map, zip
from itertools import product
from numpy import uint8
def inc(x):
return x + uint8(1)
# Create dictionary mapping from codon to integer
mapping = dict(zip(product('ATCG', repeat=3), iterate(inc, uint8(0))))
seq = sc.parallelize(["ATCGATGCATGCATGC"])
(seq
# Generate pairs (start-position, 3-gram)
.flatMap(lambda s: zip(iterate(inc, 0), sliding_window(3, s)))
# Map 3-grams to respective integers
.map(lambda (pos, seq): (pos, mapping.get(seq)))
.collect())
阅读框架显然是多余的,可以随时从起始位置获取,所以我在这里省略了它。
密码子和小整数之间的简单映射可以节省大量内存和流量。