为啥这个字典理解这么慢?请建议加快速度的方法
Posted
技术标签:
【中文标题】为啥这个字典理解这么慢?请建议加快速度的方法【英文标题】:Why is this dictionary comprehension so slow? Please suggest way to speed it up为什么这个字典理解这么慢?请建议加快速度的方法 【发布时间】:2020-12-09 21:37:53 【问题描述】:嗨,请帮助我:加快字典压缩速度;提供更好的方法或更好地理解为什么它在内部如此缓慢(例如,随着字典内存大小的增长,计算速度变慢)。我敢肯定,在不学习 C 的情况下一定有更快的方法!
classes = i : [1 if x in df['column'].str.split("|")[i] else 0 for x in df['column']] for i in df.index
输出:
1:[0,1,0...0],......, 4000:[0,1,1...0]
来自这样的 df:
data_ = 'drugbank_id': ['DB06605', 'DB06606', 'DB06607', 'DB06608', 'DB06609'],
'drug-interactions': ['DB06605|DB06695|DB01254|DB01609|DB01586|DB0212',
'DB06605|DB06695|DB01254|DB01609|DB01586|DB0212',
'DB06606|DB06607|DB06608|DB06609',
'DB06606|DB06607',
'DB06608']
pd.DataFrame(data = data_ , index=range(0,5) )
我在一个有 4000 行的 df 中执行它,列 df['column'] 包含一个由 | 分隔的 Id 字符串。每行中需要拆分的 ID 数量从 1 到 1000 不等,但是,这是针对所有 4000 个索引执行的。我在 df 的头上对其进行了测试,它似乎足够快,现在理解已经运行了 24 小时。所以也许这只是工作的绝对规模,但我觉得我可以加快速度,此时我想阻止它重新设计,但是,我害怕这会让我在速度没有太大提高的情况下倒退,所以在我这样做之前,我想得到一些想法、想法和建议。
超过 4000x4000 大小我怀疑使用系列和索引对象是另一个问题,我最好使用列表,但考虑到任务的大小,我不确定会获得多少速度,也许我会最好使用其他方法,例如 pd.apply(df, f(逐行写入 json))。我不确定 - 感谢任何帮助和教育,谢谢。
【问题讨论】:
看起来您在每次迭代时都在不必要地分割整个列。 您能否提供一些示例数据和您的预期输出?我很肯定你可以得到一个解决方案,让这个过程只需要几秒钟,最多可能一分钟。 你为什么要“预成型”“包含一串 Ids”的“df”?为什么不直接使用set
或其他更合适的数据结构?等待 24 小时表明你做错了什么! 4k 视频的像素是所有数据的一半以上,播放视频意味着每秒处理 30 次帧。你应该能够相对容易地在 100 倍内获得 Python,即正如 @ALollz 所说,几秒钟不应该是问题
@ALollz 谢谢我添加了一些示例数据。啊,好的,谢谢哈哈,我没有意识到,但这是有道理的,所以我需要使用 df.iloc[df.index == i].str.split() 在单元格级别进行拆分。哈哈一分钟会很甜蜜
@SamMason 谢谢,我想可能是缺乏经验。我会记住你的 4K 类比。 3 小时后它还在继续,所以就让它过夜,它仍然没有完成。 id 对应于与给定 id 交互的 id,它们将是唯一的,但在 df 单元中它们当前是一个字符串。你认为我应该在 df 之外这样做吗?
【参考方案1】:
这是一种方法:
import pandas as pd
# create data frame
df = pd.DataFrame('idx': [1, 2, 3, 4], 'col': ['1|2', '1|2|3', '2|3', '1|4'])
# split on '|' to convert string to list
df['col'] = df['col'].str.split('|')
# explode to get one row for each list element
df = df.explode('col')
# create dummy ID (this will become True in the final result)
df['dummy'] = 1
# use pivot to create dense matrix
df = (df.pivot(index='idx', columns='col', values='dummy')
.fillna(0)
.astype(int))
# convert each row to a list
df['test'] = df.apply(lambda x: x.to_list(), axis=1)
print(df)
col 1 2 3 4 test
idx
1 1 1 0 0 [1, 1, 0, 0]
2 1 1 1 0 [1, 1, 1, 0]
3 0 1 1 0 [0, 1, 1, 0]
4 1 0 0 1 [1, 0, 0, 1]
【讨论】:
谢谢。我喜欢你这样做的方式,通过显示所有值的矩阵/df 让一切都变得非常清晰。我添加了 df.reset_index(inplace=True) 和 df['test'].to_dict() 以获取所需格式。很快就会在大数据集上运行,就等notebook停止了。干杯【参考方案2】:您想要的输出可以使用dummies
来实现。我们拆分列stack
,并使用max
将其转换为基于原始索引的虚拟指标。然后我们使用reindex
根据'drugbank_id'
列按您想要的顺序获取它。
最后为了得到你想要的字典,我们将转置并使用to_dict
classes = (pd.get_dummies(df['drug-interactions'].str.split('|', expand=True).stack())
.max(level=0)
.reindex(df['drugbank_id'], axis=1)
.fillna(0, downcast='infer')
.T.to_dict('list'))
print(classes)
0: [1, 0, 0, 0, 0], #Has DB06605, No DB06606, No DB06607, No DB06608, No DB06609
1: [1, 0, 0, 0, 0],
2: [0, 1, 1, 1, 1],
3: [0, 1, 1, 0, 0],
4: [0, 0, 0, 1, 0]
【讨论】:
感谢@ALollz,在虚拟数据上工作正常,但是当我在实际 df 上尝试时,得到如下错误结尾,对此有什么想法吗? I cython_operation(self, kind, values, how, axis, min_count, **kwargs) 491 # 我们使用 iNaT 作为 ints 492 上的缺失值 # 所以预先转换以保护这个条件 --> 493 if (values == iNaT ).any(): 494 values = ensure_float64(values) 495 else: AttributeError: 'bool' object has no attribute 'any' @抱歉在完成之前保存 last traceback is: cython_operation(self, kind, values, how, axis, min_count, **kwargs) 491 # 我们使用 iNaT 作为 ints 492 上的缺失值 # 所以预先转换以保护它条件 --> 493 if (values == iNaT).any(): 494 values = ensure_float64(values) 495 else: AttributeError: 'bool' object has no attribute 'any' 对不起,我想这没有帮助 - 我应该将完整的追溯添加到我的问题吗? 不,我不会担心这一点,除非您从头到尾都有一个完整的示例,其中包含我的代码可以表明该问题。这是一个我从未遇到过的非常奇怪的问题,您使用的是哪个版本的pandas
?以上是关于为啥这个字典理解这么慢?请建议加快速度的方法的主要内容,如果未能解决你的问题,请参考以下文章