Добавить DataFrames с многостолбцовым индексом и перекрывающимися именами столбцов - PullRequest
1 голос
/ 05 марта 2019

У меня есть несколько фреймов данных, которые генерируются в разных итерациях цикла, как показано ниже: d1 создается в итерации 1, d2 в итерации 2 и т. д.

d1=pd.DataFrame({'PARTICIPANT_ID':['idA'],'AGE':[32],'GENDER':['male'],'colA':[20],'colB':[100]})
d2=pd.DataFrame({'PARTICIPANT_ID':['idA'],'AGE':[32],'GENDER':['male'],'colC':[1],'colD':[6]})
d3=pd.DataFrame({'PARTICIPANT_ID':['idA'],'AGE':[32],'GENDER':['male'],'colE':[60],'colF':[11]})
d4=pd.DataFrame({'PARTICIPANT_ID':['idB'],'AGE':[43],'GENDER':['female'],'colA':[30],'colB':[200]})
d5=pd.DataFrame({'PARTICIPANT_ID':['idB'],'AGE':[43],'GENDER':['female'],'colC':[2],'colD':[7]})
d6=pd.DataFrame({'PARTICIPANT_ID':['idB'],'AGE':[43],'GENDER':['female'],'colE':[70],'colF':[12]})
d7=pd.DataFrame({'PARTICIPANT_ID':['idC'],'AGE':[28],'GENDER':['female'],'colE':[56],'colF':[48]})

Я хочу продолжать объединять эти фреймы данных после каждой итерации в больший конечный фрейм данных или сохранять их в виде словарей или другого типа данных и объединять их вместе в конце цикла.

Вот как должен выглядеть вывод (только PARTICIPANT_ID может выступать в качестве индекса для этих фреймов данных):

PARTICIPANT_ID  AGE GENDER  colA    colB    colC    colD    colE    colF
idA             32  male    20.0    100.0   1.0     6.0     60      11
idB             43  female  30.0    200.0   2.0     7.0     70      12
idC             28  female  NaN     NaN     NaN     NaN     56      48

Я сейчас делаю как:

df_final = df_final.set_index(['PARTICIPANT_ID','AGE','GENDER'],inplace=True).combine_first(d1.set_index(['PARTICIPANT_ID','AGE','GENDER'],inplace=True))

где df_final - окончательный выходной кадр данных, и я повторяю этот процесс в цикле для каждого нового кадра данных, который создается в каждой итерации.

Проблема с этим типом слияния заключается в том, что он БОЛЬШОЙ МЕДЛЕННО. Может кто-нибудь, пожалуйста, предложите лучший способ добиться того же результата БЫСТРО И ЭФФЕКТИВНО.

Обратите внимание, что цикл повторяет несколько сотен тысяч записей и имеет гораздо больше столбцов, чем показано в примере выше.

1 Ответ

0 голосов
/ 05 марта 2019

Вы можете получить ту же логику с помощью concat + groupby + first, возможно, это будет быстрее для ваших реальных данных:

df_res = (pd.concat([d1, d2, d3, d4, d5, d6, d7], sort=False)
              .groupby(['PARTICIPANT_ID', 'AGE', 'GENDER']).first())
#                           colA   colB  colC  colD  colE  colF
#PARTICIPANT_ID AGE GENDER                                     
#idA            32  male    20.0  100.0   1.0   6.0  60.0  11.0
#idB            43  female  30.0  200.0   2.0   7.0  70.0  12.0
#idC            28  female   NaN    NaN   NaN   NaN  56.0  48.0

В противном случае, я бы сказал reduce, но выкажется, уже делают это:

from functools import reduce

reduce(lambda l,r: l.combine_first(r), 
       [x.set_index(['PARTICIPANT_ID', 'AGE', 'GENDER']) for x in [d1, d2, d3, d4, d5, d6, d7]])

myl = [d1, d2, d3, d4, d5, d6, d7]

%timeit pd.concat(myl, sort=False).groupby(['PARTICIPANT_ID', 'AGE', 'GENDER']).first()
#9.11 ms ± 310 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit reduce(lambda l,r: l.combine_first(r), [x.set_index(['PARTICIPANT_ID', 'AGE', 'GENDER']) for x in myl])
#61.3 ms ± 1.18 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...