首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何绕开稀疏矩阵的慢群?

如何绕开稀疏矩阵的慢群?
EN

Stack Overflow用户
提问于 2020-01-22 09:44:13
回答 2查看 377关注 0票数 6

我有一个大型矩阵(大约2亿行),描述了每天发生的操作列表(大约有10000个可能的操作)。我的最终目标是创建一个共现矩阵,显示在同一天内发生了哪些操作。

下面是一个示例数据集:

代码语言:javascript
复制
data = {'date':   ['01', '01', '01', '02','02','03'],
        'action': [100, 101, 989855552, 100, 989855552, 777]}
df = pd.DataFrame(data, columns = ['date','action'])

我试图用pd.get_dummies创建一个稀疏矩阵,但是解出矩阵并在其上使用groupby非常慢,只需6分钟就能完成5000行。

代码语言:javascript
复制
# Create a sparse matrix of dummies
dum = pd.get_dummies(df['action'], sparse = True)
df = df.drop(['action'], axis = 1)
df = pd.concat([df, dum], axis = 1)

# Use groupby to get a single row for each date, showing whether each action occurred.
# The groupby command here is the bottleneck.
cols = list(df.columns)
del cols[0]
df = df.groupby('date')[cols].max()

# Create a co-occurrence matrix by using dot-product of sparse matrices
cooc = df.T.dot(df)

我也试过:

获取非稀疏格式的虚拟数据;在矩阵aggregation;

  • going之前,

  • 使用groupby对进行稀疏格式。

但是我在第一步失败了,因为没有足够的RAM来创建这么大的矩阵。

我非常感谢你的帮助。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-01-31 10:51:37

我想出了一个答案,只使用基于this post的稀疏矩阵。代码速度很快,1000万行大约花费10秒(我之前的代码花费了5000行6分钟,无法伸缩)。

节省的时间和内存来自于使用稀疏矩阵,直到最后一步,此时需要在导出之前分解(已经很小的)共生矩阵。

代码语言:javascript
复制
## Get unique values for date and action
date_c = CategoricalDtype(sorted(df.date.unique()), ordered=True)
action_c = CategoricalDtype(sorted(df.action.unique()), ordered=True)

## Add an auxiliary variable
df['count'] = 1

## Define a sparse matrix
row = df.date.astype(date_c).cat.codes
col = df.action.astype(action_c).cat.codes
sparse_matrix = csr_matrix((df['count'], (row, col)),
                shape=(date_c.categories.size, action_c.categories.size))

## Compute dot product with sparse matrix
cooc_sparse = sparse_matrix.T.dot(sparse_matrix)

## Unravel co-occurrence matrix into dense shape
cooc = pd.DataFrame(cooc_sparse.todense(), 
       index = action_c.categories, columns = action_c.categories)
票数 3
EN

Stack Overflow用户

发布于 2020-01-22 11:38:17

有几个相当简单的简化可以考虑。

其中之一是您可以直接在max()对象上调用GroupBy,您不需要在所有列上使用花哨的索引,因为默认情况下它返回的是这个索引:

代码语言:javascript
复制
df = df.groupby('date').max()

第二,可以禁用GroupBy的排序。正如Pandas reference for groupby()所说:

:bool,默认True

对组键排序。通过关闭它来获得更好的性能。注意到,这不会影响每个组内观察的顺序。Groupby保留每个组中行的顺序。

所以也试一试:

代码语言:javascript
复制
df = df.groupby('date', sort=False).max()

第三,您还可以使用一个简单的pivot_table()来生成相同的结果。

代码语言:javascript
复制
df = df.pivot_table(index='date', aggfunc='max')

还有一种方法是回到您的"actions“DataFrame,将其转换为一个MultiIndex,并将其用于一个简单的系列,然后在其上使用unstack(),这将获得相同的结果,而不必使用get_dummies()步骤(但不确定这是否会删除您目前所依赖的一些稀疏属性)。

代码语言:javascript
复制
actions_df = pd.DataFrame(data, columns = ['date', 'action'])
actions_index = pd.MultiIndex.from_frame(actions_df, names=['date', ''])
actions_series = pd.Series(1, index=actions_index)
df = actions_series.unstack(fill_value=0)

您提供的示例DataFrame对于检查所有这些都是等价的并产生相同的结果是非常有用的,但是不幸的是,对于基准测试来说没有那么好。我建议您使用更大的数据集(但仍比实际数据小10倍或40-50倍),然后对操作进行基准测试,以检查它们所用的时间。

如果您使用的是木星(或另一个IPython shell),则可以使用%timeit命令对表达式进行基准测试。

这样你就可以进入:

代码语言:javascript
复制
%timeit df.groupby('date').max()
%timeit df.groupby('date', sort=False).max()
%timeit df.pivot_table(index='date', aggfunc='max')
%timeit actions_series.unstack(fill_value=0)

比较结果,然后放大并检查整个运行是否会在可接受的时间内完成。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59856694

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档