Pandas分组操作的性能问题

3
我正在运行一台拥有大量 RAM(190GB)的工作站。 我们需要在数百万条记录的数据集上进行 groupby 操作[通常包含 2 个 ID 列、1 个类型 ID 列、1 个日期列和 3-5 个分类列](在 10-30 M 范围内),同时生成聚合列的列表。
我们的问题是性能非常慢。在 R 中运行相同的代码不到一个小时。 当前的测试数据集仅有 770 万条记录。数据如下:
ID1         ID2         typeid    date_      cat1    cat2   cat3
12554876563 1435465465  09238423  2013-04-2  cat11   cat21  cat31
12554876563 1435465465  984375    2012-11-12 cat12   cat21  cat33
125543213   12554876563 01248423  2012-04-2  cat11   cat23  cat31
5436236563  125543213   09275423  2017-04-2  cat13   cat24  cat32

groupby 的用法如下:

def agg_col(var):
    li = ';'.join([str(i) for i in set(var.dropna())])
    return li

    df = ( df.groupby(['ID1','ID2']).agg(lambda x: agg_col(x))
             .assign(weight=df.groupby(['ID1','ID2']).size())

我们也尝试使用dask作为该帖子中建议的方式,但仍然遇到问题, aggregate-agg 进程需要一个小时以上的时间。
如有建议,请提出。

你进行了性能分析吗?我认为列表推导式中的 str 函数占用了大部分时间。 - mdurant
如果我需要生成一个以 ; 为分隔符的列表,我有哪些选项?也许在运行 groupby 之前对所有列进行矢量化处理。 - skibee
你能否将一部分数据添加到这个问题中?可以从几个不同的组中选择4或5行。 - Scott Boston
也许 https://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.str.join.html 可以帮助你?我想知道为什么你想要这样的表示。 - mdurant
数据稍后会被加载到 neo4j 中。如果 ';' 分隔符有问题,我们可以使用 --array-delimiter。但是我们仍然需要将值连接成列表。 - skibee
显示剩余2条评论
2个回答

1
将“类别”系列更改为“整数”确实提高了性能,但仍然不够好。
我们的解决方案是将其转储到sqlite中-> groupby ->并重新加载。
以下数据集在不到5分钟内完成。
con = sqlite3.connect('/path/to/tempdb.db')
df.to_sql('data', con, if_exists='replace')
sql_index = 'create index id12_idx on data(ID1, ID2)'
con.execute(sql_index)
sql_gp = 'SELECT ID1, ID2, GROUP_CONCAT(DISTINCT typeid), GROUP_CONCAT(DISTINCT date_), GROUP_CONCAT(DISTINCT cat1), GROUP_CONCAT(DISTINCT cat2), GROUP_CONCAT(DISTINCT cat3) from data GROUP BY ID1, ID2')
df = pd.read_sql_query(sql_gp, con)

顺便提一下,我们尝试使用Dask框架来实现这个问题,但是只有有限的成功。 - skibee

0
你可以试试这个:
我认为你正在进行两个groupby,但我怀疑你可以通过在agg方法中使用列表来完成一个groupby。此外,我认为我们可以摆脱那个列表推导式,并使用unique和join。
df.groupby(['ID1','ID2']).agg([lambda x: ';'.join(x.dropna().unique()),'size'])

而且你可以使用.rename(columns={'<lambda>':'agg_col','size':'weight'})重命名你的列。


agg 的参数可以是一个将列名映射到函数的字典,对吗? - mdurant
@mdurant,那个字典重命名是在几个版本之前删除的。我想是在0.19左右。 - Scott Boston
1
哦,不幸啊。看起来这是一种不错的简洁方式来表达该过程。 - mdurant
顺便说一句 - 我尝试了上面的代码,已经运行了一个多小时。 - skibee
1
@JosephBerry 好的...也许我们需要考虑使用numpy。你应该将这个问题编辑一下,加上numpy作为标签。 - Scott Boston

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接