【问题标题】:How to increase computational speed of mapping function to a dataframe column in pandas如何提高映射函数到熊猫中数据框列的计算速度
【发布时间】:2019-10-05 07:48:58
【问题描述】:

我正在数据框中创建一个新列,该列基于整个数据框中的其他值。我找到了几种方法(如下所示),但是在处理大型数据集时它们非常慢(运行 500k 行需要 1 小时)。我希望加快这个过程的速度。

我尝试将 .apply 与 lambda 函数一起使用。我还使用 .map 获取要放入新列的列表。这两种方法都可以,但是太慢了。

values = {'ID': ['1','2','3','4','1','2','3'],
        'MOD': ['X','Y','Z','X','X','Z','Y'],
        'Period': ['Current','Current','Current','Current','Past','Past','Past']
        }

df = DataFrame(values,columns= ['ID', 'MOD','Period'])

df['ID_MOD']=df['ID']+df['MOD']

def funct(identifier, indentifier_modification,period):
    if period=="Current":
        if (df.ID==identifier).sum()==1:
            return "New"     
        elif (df.ID_MOD==indentifier_modification).sum()==1:
            return "Unique"
        else:
            return "Repeat"
    else:
        return "n/a"

初始df:

  ID MOD   Period ID_MOD
0  1   X  Current     1X
1  2   Y  Current     2Y
2  3   Z  Current     3Z
3  4   X  Current     4X
4  1   X     Past     1X
5  2   Z     Past     2Z
6  3   Y     Past     3Y

下面是两个太慢的方法: 1)

df['new_column']=df.apply(lambda x:funct(x['ID'],x['ID_MOD'],x['Period']), axis=1)

2)

df['new_column']=list(map(funct,df['ID'],df['ID_MOD'],df['Period']))

预期的最终df:

  ID MOD   Period ID_MOD new_column
0  1   X  Current     1X     Repeat
1  2   Y  Current     2Y     Unique
2  3   Z  Current     3Z     Unique
3  4   X  Current     4X        New
4  1   X     Past     1X        n/a
5  2   Z     Past     2Z        n/a
6  3   Y     Past     3Y        n/a

没有错误信息;运行大型数据集的代码只需约 1 小时。

【问题讨论】:

  • 如果计算可以并行化也许你应该试试?

标签: python dataframe


【解决方案1】:

您当前的代码目前按 O(N**2) 缩放,其中 N 是行数。如果您的 df 真的是 500k 行,这将需要很长时间!你真的想使用计算复杂度低得多的 numpy 和 pandas 代码。

pandas 中内置的aggregations 可以代替您使用sum,以及了解pandas 如何进行索引和merge。在你的情况下,我可以很容易地将 500k 行减少到不到一秒。

首先定义一个虚拟数据集:

import numpy as np
import pandas as pd

N = 500_000

df = pd.DataFrame({
    'id': np.random.choice(N//2, N),
    'a': np.random.choice(list('XYZ'), N),
    'b': np.random.choice(list('CP'), N),
})

接下来,我们可以对您的各个组进行汇总:

ids = df.groupby(['id']).size().rename('ids')
idas = df.groupby(['id','a']).size().rename('idas')

接下来我们可以将这些聚合加入原始数据集

尽可能多地减少数据始终是一个好主意,在您的情况下,Past 值总是得到n/a 的值,因为它们占用了一半的数据,所以工作量似乎是一半:

df2 = df.loc[df['b'] == 'C',]
df2 = pd.merge(df2, ids, left_on=['id'], right_index=True)
df2 = pd.merge(df2, idas, left_on=['id','a'], right_index=True)

最后,我们使用 numpy 中的 where 对所有条件进行矢量化处理,因此工作速度更快,然后使用 pandas 索引将所有内容有效地重新组合在一起,然后修补缺失值

df2['out'] = np.where(
    df2['ids'] == 1, 'New',
    np.where(df2['idas'] == 1, 'Unique', 'Repeat'))

df['out'] = df2['out']
df['out'].fillna('n/a', inplace=True)

希望对您有所帮助!作为参考,我的笔记本电脑上 500k 行的上述运行时间约为 320 毫秒

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-13
    • 1970-01-01
    • 2015-01-28
    • 1970-01-01
    • 2022-11-14
    • 2018-07-16
    • 2015-04-25
    • 2016-12-30
    相关资源
    最近更新 更多