从 pandas 数据帧构建频率字典而不循环

Building a frequency dictionary from a pandas dataframe without looping

我需要从 pandas 系列(来自下面数据框中的 'amino_acid' 列)制作一个频率字典,它还为字典中的每个条目添加一个相邻的行(来自 'templates' 列)。

    templates   amino_acid
0   118       CAWSVGQYSNQPQHF
1   635       CASSLRGNQPQHF
2   468       CASSHGTAYEQYF
3   239       CASSLDRLSSGEQYF
4   51        CSVEDGPRGTQYF

根据 this post,我目前迭代数据帧的方法似乎效率低下,甚至是一种反模式。我如何才能改进 efficiency/use 最佳实践?

我目前的做法:

sequence_counts = {}
seqs = list(zip(df.amino_acid, df.templates))

for seq in seqs:
    if seq[0] not in sequence_counts:
        sequence_counts[seq[0]] = 0
    sequence_counts[seq[0]] += seq[1]

我见过有人用下面的方法,但不知道如何调整它以添加每个相应的 'templates' 条目:

sequence_counts = df['amino_acid'].value_counts().to_dict()

任何 help/feedback 将不胜感激! :)

根据你的问题我的理解是你希望创建一个字典 key/value 这样 key=amino_acidvalue is the frequency = templates

由于您已经成功创建了 seqs = list(zip(df.amino_acid, df.templates))

的元组

你的字典可以构造为:

sequence_counts = dict(seqs)

一行:

sequence_counts = dict(zip(df.amino_acid, df.templates))

或者你可以从这种性质做一些事情:

sequence_counts = dict([(k,v) for k,v in zip(df.amino_acid,df.templates)])

刚刚测试了@Nolan Conaway 评论的代码,这是最好的做法:

df.groupby('amino_acid').templates.sum()

有了这个,你就得到了一个包含你所需要的数据框,而且由于它使用了所有数据框的原生函数,运行速度更快,当然也更简洁、简短和干净。

对于速度,我在 10^4 数据帧中测量了经过的时间,这段代码比我在下面的回答快了大约三个数量级(0.007 对 4.3 秒)。

Nolan 应该将评论放在答案中,这样他就可以通过巧妙巧妙地使用 pandas dataframe api.

我会在这里留下我的答案,以防有人觉得评论有用。

我不完全了解 pandas api,但我找不到 api 的任何组合来满足您的需求(但 Nolan 做到了!) .但似乎您可以通过不创建列表或显式压缩数据来大大改进您的代码。如果您使用迭代器而不是那些结构,您可以提高性能。

例如,在 list(zip(df.amino_acid, df.templates)) 中,list 并不是真正必要的,因为 zip 已经 return 是一个列表。此外,您可以使用 itertools 库的 izip 函数,该函数无需构建列表即可提供迭代器。此外,最好使用 pandas 迭代器构造函数而不是调用列(据我所知, return 也是列表中数据的副本,所以你还有另一个迭代在数据帧上)。

无论如何,我会尝试这样的事情。

sequence_counts = { }
for _, row in df.iterrows():
    t, aa = row['templates'], row['amino_acid']
    s = sequence_counts.get(aa, 0)
    sequence_counts[aa] = s + t

通过这种方式,您实际上只对数据进行了一次迭代,使用数据框为您提供的迭代器。