2016-02-12 4 views
1

В моей информационной кадре df1 Я хочу присвоить новое значение val1 в первых строк каждой группы. Новое значение зависит от группы и сохраняется в df2.Эффективно присваивать значение первой строке в groupby

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

Я придумал лучшее решение при написании этого сообщения, что примерно в 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 s, SYS: 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 с, SYS: 1,2 сек, всего: 4,62 сек Стена Время: 4,78 сек

Смежные вопросы