Панды df.объединяют неожиданное поведение сортировки

#python #pandas #dataframe

Вопрос:

Я не могу понять, почему я получаю другое поведение для простого слияния в индексе обоих DFS. Основываясь на документах, я ожидаю, что результирующий фрейм данных будет соответствовать правильному индексу DF.

Случай 1

 staff= pd.DataFrame([1,2,3],index=['Kelly','Sally','James'])
student= pd.DataFrame(['Texas','Califa','South Dakota'],index=['James','Mike','Sally'])
pd.merge(student,staff,left_index=True,right_index=True,how='right')
 

Я получаю:

         0_x             0_y
Kelly   NaN             22
Sally   South Dakota    38
James   Texas           45
 

который следует за правильным индексом DF (персонала)

Случай 2

 left = pd.DataFrame(   { "A": ["A0", "A1", "A2", "A3"], "B": ["B0", "B1", "B2", "B3"]},
                                 index = ["K0", "K1", "K0", "K3"])
right = pd.DataFrame({"C": ["C0", "C1"], "D": ["D0", "D1"]}, index=["K1", "K0"])
pd.merge(left,right,left_index=True,right_index=True,how='right')
 

Я получаю

      A  B   C   D
K0  A0  B0  C1  D1
K0  A2  B2  C1  D1
K1  A1  B1  C0  D0
 

НО я ожидал, что:

      A  B   C   D
K1  A1  B1  C0  D0
K0  A0  B0  C1  D1
K0  A2  B2  C1  D1
 

как и в случае 1

Спасибо.

Ответ №1:

Проблема заключается в дублировании значений в индексе, что требует некоторых накладных расходов для позиционного различения строк с одним и тем же индексом. Этот процесс будет происходить независимо от типа merge . Примечание join также будет демонстрировать такое же поведение.

Чтобы обойти проблему , можно reset_index объединить столбец "index" в обоих кадрах, а затем set_index в объединенном кадре, чтобы вернуть "index" столбец в индекс кадра данных.

 merged = pd.merge(
    left.reset_index(),  # Create Index Column on left
    right.reset_index(),  # Create Index Column on right
    on='index', how='right'
).set_index('index').rename_axis(None)  # Put index back
 

merged :

      A   B   C   D
K1  A1  B1  C0  D0
K0  A0  B0  C1  D1
K0  A2  B2  C1  D1
 

Почему работает случай 1? Часть процесса выравнивания, которая вызывает «неожиданное» поведение, — это фаза, в которой используется позиционное упорядочение для различения разных строк с одним и тем же индексом.

Обратите внимание, что произойдет, если мы добавим повторяющееся значение индекса в первый пример. Повторяющиеся записи в столбце слияния требуют особого ухода.

 staff = pd.DataFrame([1, 2, 3], index=['Sally', 'Sally', 'James'])
student = pd.DataFrame(['Texas', 'Califa', 'South Dakota'],
                       index=['James', 'Mike', 'Sally'])
 

staff :

        0
Sally  1  # Kelly Changed to Sally
Sally  2 
James  3
 

Теперь merge производит:

 merged = pd.merge(student, staff, left_index=True, right_index=True,
                  how='right')
 

merged :

                 0_x  0_y
James         Texas    3
Sally  South Dakota    1  # Sally is now grouped and sorted last
Sally  South Dakota    2
 

Почему? Ну, при доступе к индексу в местоположении «Салли», какую Салли мы имеем в виду? И какое значение следует объединить? Этот вопрос решается путем сортировки и группировки значений, чтобы они отображались в порядке, и «Салли (1)» и «Салли (2)» можно различать как отдельные строки.

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


Почему обходной путь работает? Ну, значение столбца «Салли» при индексе 0 и значение столбца «Салли» и индекс 1 однозначно идентифицированы.

Комментарии:

1. Почему, однако, выравнивание индекса не происходит в Случае 1?

2. Выравнивание действительно происходит. На самом деле проблема заключается в части выравнивания «групповые ключи», которая вызывает проблему. взгляните на мое обновление

3. Генри, теперь все кликает с твоим обновленным комментарием. Мне любопытно, хотя откуда вы это знаете? Это связано с чтением исходного кода или с опытом работы с той же проблемой? Руководство пользователя явно не описывает это поведение. Я пытаюсь узнать больше о том, что происходит под капотом с Пандами. Спасибо.

4. И то, и другое? Я прочитал довольно много исходного кода. Но и по опыту. В данном случае это был исходный код. Слияние с этими не уникальными индексами в конечном итоге приведет к _join_non_unique . Вы можете заметить , что get_join_indexers имеет sort=True независимо от того, как была задана сортировка при первоначальном слиянии. В итоге вы получите left_index [0, 2, 1] и правильный индекс [1, 1, 0] .

Ответ №2:

В соответствии с документацией https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.merge.html pd.merge имеет возможность передать сортировку в аргументе , который сортирует ключ соединения, как в вашем, — это индекс.

 staff= pd.DataFrame([1,2,3],index=['Kelly','Sally','James'])
student= pd.DataFrame(['Texas','Califa','South Dakota'],index= 
['James','Mike','Sally'])
pd.merge(student,staff,left_index=True,right_index=True,how='right', sort=True) 



        0_x    0_y
James   Texas   3
Kelly   NaN     1
Sally   South Dakota    2
 

вы также можете использовать индекс сортировки

 left = pd.DataFrame(   { "A": ["A0", "A1", "A2", "A3"], "B": ["B0", "B1", "B2", "B3"]},
                             index = ["K0", "K1", "K0", "K3"])
right = pd.DataFrame({"C": ["C0", "C1"], "D": ["D0", "D1"]}, index=["K1", "K0"])
pd.merge(left,right,left_index=True,right_index=True,how='right').sort_index(ascending=True)

        A   B   C   D
  K1    A1  B1  C0  D0
  K0    A0  B0  C1  D1
  K0    A2  B2  C1  D1