如何提高映射功能到熊猫数据框列的计算速度

时间:2019-10-04 21:23:53

标签: python dataframe

我正在基于整个数据框中的其他值在数据框中创建一个新列。我发现了几种方法(如下所示),但是在处理大型数据集时(运行50万行需要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个小时即可运行大型数据集。

1 个答案:

答案 0 :(得分:0)

您当前的代码当前缩放为O(N ** 2),其中N是行数。如果您的df确实有50万行,这将需要很长时间!您真的想使用numpy和pandas的代码,它们的计算复杂度要低得多。

内置到大熊猫中的aggregations会大大代替您使用sum,就像了解熊猫如何建立索引和merge一样。在您的情况下,我可以很容易地将50万行减少到不到一秒。

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

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)

希望其中一些帮助!供参考,上面的代码在我的笔记本电脑上以50万行在320ms内运行