Значение по умолчанию / заполнение для * multi-key * внешних объединений

NB: Сообщение ниже – это «многозадачный» аналог предыдущего вопроса . Решения для этого более раннего вопроса работают только для случая, когда соединение принадлежит одному ключу, и мне не совсем ясно, как обобщить эти решения для случая с несколькими ключами, представленного ниже. Поскольку IME, изменяя уже ответивший вопрос таким образом, что дисквалифицирует полученные ответы, не одобряется в SO, я публикую этот вариант отдельно. Я также разместил вопрос для Meta SO о том, следует ли удалить этот пост и вместо этого изменить исходный вопрос за счет аннулирования его текущих ответов.


Ниже представлены версии для подростков / игрушек с более крупными / сложными файлами данных, с которыми я работаю:

>>> A key1 key2 uvwx 0 a G 0.757954 0.258917 0.404934 0.303313 1 b H 0.583382 0.504687 NaN 0.618369 2 c I NaN 0.982785 0.902166 NaN 3 d J 0.898838 0.472143 NaN 0.610887 4 e K 0.966606 0.865310 NaN 0.548699 5 f L NaN 0.398824 0.668153 NaN key1 key2 yz 0 a G 0.867603 NaN 1 b H NaN 0.191067 2 c I 0.238616 0.803179 3 d G 0.080446 NaN 4 e H 0.932834 NaN 5 f I 0.706561 0.814467 

(FWIW, в конце этого сообщения я предоставляю код для создания этих кадров данных.)

Я хочу создать внешнее соединение этих кадров данных в столбцах key1 и key2 таким образом, чтобы новые позиции, вызванные внешним соединением, получили значение по умолчанию 0.0. IOW, желаемый результат выглядит следующим образом:

  key1 key2 uvwxyz 0 a G 0.757954 0.258917 0.404934 0.303313 0.867603 NaN 1 b H 0.583382 0.504687 NaN 0.618369 NaN 0.191067 2 c I NaN 0.982785 0.902166 NaN 0.238616 0.803179 3 d J 0.898838 0.472143 NaN 0.610887 0.000000 0.000000 4 e K 0.966606 0.86531 NaN 0.548699 0.000000 0.000000 5 f L NaN 0.398824 0.668153 NaN 0.000000 0.000000 6 d G 0.000000 0.000000 0.000000 0.000000 0.080446 NaN 7 e H 0.000000 0.000000 0.000000 0.000000 0.932834 NaN 8 f I 0.000000 0.000000 0.000000 0.000000 0.706561 0.814467 

(Заметим, что этот желаемый результат содержит некоторые NaN, а именно те, которые уже присутствовали в A или B )

Метод merge получает меня туда-сюда, но значения по умолчанию для заполнения – NaN, а не 0.0:

 >>> C = pandas.DataFrame.merge(A, B, how='outer', on=('key1', 'key2')) >>> C key1 key2 uvwxyz 0 a G 0.757954 0.258917 0.404934 0.303313 0.867603 NaN 1 b H 0.583382 0.504687 NaN 0.618369 NaN 0.191067 2 c I NaN 0.982785 0.902166 NaN 0.238616 0.803179 3 d J 0.898838 0.472143 NaN 0.610887 NaN NaN 4 e K 0.966606 0.865310 NaN 0.548699 NaN NaN 5 f L NaN 0.398824 0.668153 NaN NaN NaN 6 d G NaN NaN NaN NaN 0.080446 NaN 7 e H NaN NaN NaN NaN 0.932834 NaN 8 f I NaN NaN NaN NaN 0.706561 0.814467 

Метод fillna не дает желаемого результата, так как он изменяет некоторые позиции, которые следует оставить без изменений:

 >>> C.fillna(0.0) key1 key2 uvwxyz 0 a G 0.757954 0.258917 0.404934 0.303313 0.867603 0.000000 1 b H 0.583382 0.504687 0.000000 0.618369 0.000000 0.191067 2 c I 0.000000 0.982785 0.902166 0.000000 0.238616 0.803179 3 d J 0.898838 0.472143 0.000000 0.610887 0.000000 0.000000 4 e K 0.966606 0.865310 0.000000 0.548699 0.000000 0.000000 5 f L 0.000000 0.398824 0.668153 0.000000 0.000000 0.000000 6 d G 0.000000 0.000000 0.000000 0.000000 0.080446 0.000000 7 e H 0.000000 0.000000 0.000000 0.000000 0.932834 0.000000 8 f I 0.000000 0.000000 0.000000 0.000000 0.706561 0.814467 

Как я могу добиться желаемого результата эффективно? (Здесь важны показатели производительности, потому что я намерен выполнить эту операцию на гораздо больших кадрах данных, чем те, которые показаны здесь.)


ВАЖНО: для того, чтобы сохранить пример минимальным, я сделал multikey состоящий всего из двух столбцов; на практике количество ключей в многоключевом ключе может быть значительно больше. Предлагаемые ответы должны быть пригодны для мульти-ключей, состоящих как минимум из полудюжины столбцов.


FWIW, ниже – код для генерации примерных кадров данных A и B

 from pandas import DataFrame from collections import OrderedDict from random import random, seed def make_dataframe(rows, colnames): return DataFrame(OrderedDict([(n, [row[i] for row in rows]) for i, n in enumerate(colnames)])) maybe_nan = lambda: float('nan') if random() < 0.4 else random() seed(0) A = make_dataframe([['A', 'g', maybe_nan(), maybe_nan(), maybe_nan(), maybe_nan()], ['B', 'h', maybe_nan(), maybe_nan(), maybe_nan(), maybe_nan()], ['C', 'i', maybe_nan(), maybe_nan(), maybe_nan(), maybe_nan()], ['D', 'j', maybe_nan(), maybe_nan(), maybe_nan(), maybe_nan()], ['E', 'k', maybe_nan(), maybe_nan(), maybe_nan(), maybe_nan()], ['F', 'l', maybe_nan(), maybe_nan(), maybe_nan(), maybe_nan()]], ('key1', 'key2', 'u', 'v', 'w', 'x')) B = make_dataframe([['A', 'g', maybe_nan(), maybe_nan()], ['B', 'h', maybe_nan(), maybe_nan()], ['C', 'i', maybe_nan(), maybe_nan()], ['D', 'g', maybe_nan(), maybe_nan()], ['E', 'h', maybe_nan(), maybe_nan()], ['F', 'i', maybe_nan(), maybe_nan()]], ('key1', 'key2', 'y', 'z')) 

One Solution collect form web for “Значение по умолчанию / заполнение для * multi-key * внешних объединений”

Установите keys как индекс двух DF's :

 def index_set(frame, keys=['key1', 'key2']): frame.set_index(keys, inplace=True) return frame 

Подмножество DF's содержащее значения NaN :

 def nulls(frame): nulls_in_frame = frame[frame.isnull().any(axis=1)].reset_index() return nulls_in_frame 

Присоединитесь к двум Df's . Объединение объединенного DF с каждым из поднабора NaN содержащего DF's и сбросить дублированные значения, заполняя оставшиеся NaN оставленные 0.

Затем, используя combine_first чтобы исправить значения, используя операцию цепочки с объединенным DF .

 def perform_join(fr_1, fr_2, keys=['key1', 'key2']): fr_1 = index_set(fr_1); frame_2 = index_set(fr_2) frame = fr_1.join(fr_2, how='outer').reset_index() cat_fr_1 = pd.concat([frame, nulls(fr_1)]).drop_duplicates(keys, keep=False).fillna(0) cat_fr_2 = pd.concat([frame, nulls(fr_2)]).drop_duplicates(keys, keep=False).fillna(0) fr_1_join = frame.combine_first(frame.fillna(cat_fr_1[fr_1.columns])) joined_frame = fr_1_join.combine_first(frame.fillna(cat_fr_2[fr_2.columns])) return joined_frame 

В заключение,

 perform_join(A, B) 

Образ

  • Как выбрать ячейки больше, чем значение в многоиндексном кадре данных Pandas?
  • Почему, если я помещаю несколько пустых рядов Pandas в hdf5, размер hdf5 настолько велик?
  • Как получить ежемесячное среднее значение в пандах, используя groupby
  • Python pandas integer YYYYMMDD для datetime
  • Pandas: получать значения индекса и столбцов каждого значения
  • какова обратная функция квантиля на серии панд?
  • Pandas: Как создать кадр данных случайных чисел?
  • Посмотрите и замените значения в списке (pandas)
  •  
    Interesting Posts for Van-Lav
    Python - лучший язык программирования в мире.