有效地为groupby中的第一行赋值

时间:2016-02-12 10:02:05

标签: python pandas

在我的数据框df1中,我想在每个组的第一个行中为val1分配一个新值。新值取决于组,并存储在df2

import pandas as pd
df1 = pd.DataFrame({'group': list('aaabbb'), 'val1': [2, 3, 6, 3, 7, 10]})
print df1
#  group  val1
#0     a     2
#1     a     3
#2     a     6
#3     b     3
#4     b     7
#5     b    10
​
df2 = pd.DataFrame({'group': ['a', 'b'], 'val2': [1, 2]})
print df2
#  group  val2
#0     a     1
#1     b     2

# Desired Output:
#  group  val1
#0     a     1  <- updated
#1     a     3
#2     a     6
#3     b     2  <- updated
#4     b     7
#5     b    10

我的第一个解决方案是合并两个数据框,并使用自定义函数将val2分配给第一行中的val1,如此post中所述。这有效,但速度很慢,内存使用率很高:

df3 = pd.merge(df1, df2, on='group')

def set_first_value(group):
    group['val1'].iat[0] = group['val2'].iat[0]
    return group

df3.groupby('group').apply(set_first_value)
df3 = pd.merge(df1, df2, on='group')

是否有更有效的方法来更改每个组中第一个元素的值?

1 个答案:

答案 0 :(得分:1)

我在撰写这篇文章时提出了一个更好的解决方案,速度提高了10倍。它使用groupby.first()

以下是基准:

# setup
import pandas as pd
import numpy as np
n = 100000
m = 100
df1 = pd.DataFrame({'group': range(n)*m, 'val1': range(n*m)})
df2 = pd.DataFrame({'group': range(n), 'val2': np.random.randint(1,100, size=n)})

使用客户功能的较慢方法:

%%time
df3 = pd.merge(df1, df2, on='group')

def set_first_value(group):
    group['val1'].iloc[0] = group['val2'].iloc[0]
    return group

df3.groupby('group').apply(set_first_value)

CPU时间:用户55.9秒,系统:2.81秒,总计:58.7秒 壁挂时间:59.8秒

使用groupby.first()的更快方法:

%%time
df3 = pd.merge(df1, df2, on='group')
df3['ix'] = df3.index
ix_first = df3.groupby('group').first()['ix']
df3['val1'] = df3['val2'].where(df3['ix'].isin(ix_first), df3['val1'])

CPU时间:用户3.41秒,系统:1.2秒,总计:4.62秒 壁挂时间:4.78秒