从 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_acid
和 value 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
通过这种方式,您实际上只对数据进行了一次迭代,使用数据框为您提供的迭代器。
我需要从 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_acid
和 value 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
通过这种方式,您实际上只对数据进行了一次迭代,使用数据框为您提供的迭代器。