Объединение двух фреймов данных pandas по идентификатору и году, в котором отсутствуют значения года - PullRequest
2 голосов
/ 25 февраля 2020

У меня есть два кадра данных (dfA и dfB) с выборкой из обоих приведенных ниже. Я хочу присоединиться к фреймам данных, чтобы получить результат, полученный

dfA
Id, year, B, D
1,  2010, 15, 33
1,  2011, 24, 72
1,  2012, 30, 16

dfB
Id, year, A, C
1,  2009, 100, 1
1,  2010, 75, 7
1,  2012, 60, 3
1, 2013, 42, 4

Result
Id, year, A, B, C, D
1, 2009,100, 0, 1, 0
1, 2010,75,15, 7, 33
1, 2011,0, 24, 0, 72
1, 2012,60, 30, 3, 16
1, 2013,42, 0, 4, 0

Попытка

Я экспериментировал с pandas .merge, пробуя внутренние, внешние, левые и правые соединения, но не смог получить желаемый результат!

result = pd.merge(dfA,dfB,on=['Id','year'], how = 'outer')

Любые советы будут с благодарностью!

Ответы [ 5 ]

3 голосов
/ 25 февраля 2020

Альтернативой слиянию в этом случае является pandas concat с конкатенацией по оси столбцов:

(pd.concat([df1.set_index(['Id','year']),
            df.set_index(['Id','year'])],axis=1)
 .reset_index()
 .fillna(0)
.reindex(columns=['Id','year','A','B','C','D'])
)

    Id  year    A       B   C   D
0   1,  2009,   100,    0   1.0 0.0
1   1,  2010,   75,     15, 7.0 33.0
2   1,  2011,   0       24, 0.0 72.0
3   1,  2012,   60,     30, 3.0 16.0
4   1,  2013,   42,     0   4.0 0.0
3 голосов
/ 25 февраля 2020

merge имеет правильный вывод, нам просто нужно заказать и sort_values

s=pd.merge(df1,df2,on=['Id','year'], how = 'outer').\
      sort_index(level=0,axis=1).sort_values(['Id', 'year']).fillna(0)
s
Out[81]: 
       A     B    C     D   year  Id
3  100.0   0.0  1.0   0.0   2009   1
0   75.0  15.0  7.0  33.0   2010   1
1    0.0  24.0  0.0  72.0   2011   1
2   60.0  30.0  3.0  16.0   2012   1
4   42.0   0.0  4.0   0.0   2013   1
2 голосов
/ 25 февраля 2020

fillna с downcast='infer'

И дерзкий способ сортировки столбцов

result = dfA.merge(dfB, 'outer').fillna(0, downcast='infer')
key = lambda x: (x not in {'Id', 'year'}, x)
result[sorted(result, key=key)]

   Id  year    A   B  C   D
0   1  2010   75  15  7  33
1   1  2011    0  24  0  72
2   1  2012   60  30  3  16
3   1  2009  100   0  1   0
4   1  2013   42   0  4   0

stack и append

I не нравится это лучше, а просто добавляет цвет к ландшафту ответа

dfA.set_index(['Id', 'year']).stack().append(
    dfB.set_index(['Id', 'year']).stack()
).unstack(fill_value=0).reset_index()

   Id  year    A   B  C   D
0   1  2009  100   0  1   0
1   1  2010   75  15  7  33
2   1  2011    0  24  0  72
3   1  2012   60  30  3  16
4   1  2013   42   0  4   0
2 голосов
/ 25 февраля 2020

Поскольку столбцы Id и year фактически используются в качестве индекса, может иметь смысл сделать их индексами и использовать объединение:

dfA.set_index(['Id', 'year']).join(dfB.set_index(['Id', 'year']), how = 'outer'
              ).fillna(0).astype(int)[list('ABCD')].reset_index()

дает:

   Id  year    A   B  C   D
0   1  2009  100   0  1   0
1   1  2010   75  15  7  33
2   1  2011    0  24  0  72
3   1  2012   60  30  3  16
4   1  2013   42   0  4   0
1 голос
/ 25 февраля 2020

merge дает "правильные результаты". Однако, NA должны быть заполнены и преобразованы в int и упорядочены столбцы. Один из способов получить правильный порядок столбцов - использовать менее желательное «жесткое кодирование», которое, как мне показалось, работает лучше, чем автоматическая c сортировка, скажем, sort_index(axis=1) или каким-либо другим способом.

desired_col_order = ['id','year','a','b','c','d']
B.merge(A,on=['id','year'], how='outer').sort_values(['id','year'])
 .fillna(0).astype(int)[desired_col_order]

производит:

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...