несколько операций над двумя фреймами данных с использованием pandas - PullRequest
0 голосов
/ 05 мая 2020

Это расширение моего предыдущего вопроса введите здесь описание ссылки

У меня есть два фрейма данных df1 и df2 разной длины и два столбца в качестве ключевых столбцов. Я хотел бы выполнить несколько операций с этими фреймами данных следующим образом:

  1. Замена только пустых ячеек (NAs) в df1 соответствующими значениями из df2 на основе ключевых столбцов
  2. для каждого пара ключевых столбцов, ячейки из обоих фреймов данных, значения которых противоречат друг другу, должны быть представлены в новом фрейме данных

df1

id_col1   id_col2   name    age    sex
---------------------------------------
101         1M              21  
101         3M              21      M
102         1M      Mark    25  

df2

id_col1    id_col2    name     age     sex
-------------------------------------------
101          1M       Steve             M
101          2M                         M
101          3M       Steve    25   
102          1M       Ria      25       M
102          2M       Anie     22       F

После выполнения операции 1, т.е. замены NA в df1 соответствующими значениями из df2, я должен получить следующее:

result_1

id_col1    id_col2    name     age     sex
-------------------------------------------
101         1M        Steve    21      M
101         3M        Steve    25      M
102         1M        Mark     25      M

После выполнения операции 2, т.е. конфликтующих ячеек в df1 и df2 для тех же ключевых столбцов, я должен получить следующее:

result_2

id_col1    id_col2    name     age     sex
-------------------------------------------
101          3M                21   
101          3M                25   
102          1M        Mark     
102          1M        Ria      

Может ли кто-нибудь помочь в их решении?

Ответы [ 2 ]

1 голос
/ 06 мая 2020

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

Установите столбцы id как индекс, используйте combine_first, как в исходном сообщении. Однако, поскольку combine_first возвращает объединение меток обоих фреймов данных (то есть строк и столбцов), после его применения выберите только те индексы, которые принадлежат df1

idx = ['id_col1', 'id_col2']
df1 = df1.set_index(idx)
df2 = df2.set_index(idx)
result_1 = df1.combine_first(df2).loc[df1.index]
# result_1 outputs:
                  name   age sex
id_col1 id_col2
101     1M       Steve  21.0   M
        3M       Steve  21.0   M
102     1M        Mark  25.0   M

Чтобы сгенерировать result_2, сначала следуйте подходу, предложенному в предыдущем посте:

mask = pd.notnull(df1) & ~df1.eq(df2) & pd.notnull(df2)
result_2 = pd.concat([df1[mask], df2[mask]]).dropna(how='all')

Это генерирует желаемые данные, однако порядок немного отличается от того, что вы представляете, потому что df1[mask] накладывается поверх df2[mask].

отсортируйте по индексу, чтобы получить окончательный результат:

result_2.sort_index()
# outputs 
                 name   age  sex
id_col1 id_col2
101     3M        NaN  21.0  NaN
        3M        NaN  25.0  NaN
102     1M       Mark   NaN  NaN
        1M        Ria   NaN  NaN

Единственное отличие этого решения от решения, представленного в первом посте, - это дополнительные ...loc[df1.index] и result_2.sort_index()

1 голос
/ 06 мая 2020

Использование df1

enter image description here

df2

enter image description here

Объединить

df3=df2.merge(df1, left_index=True,right_index=True,suffixes=('_left', ''), how='left')

Решение 1, используйте np.where для передачи деталей и удаления ненужных строк

df3['name']=np.where(df3['name'].isna(),df3['name_left'],df3['name'])
df3['sex']=np.where(df3['sex_left'].isna(),df3['sex'],df3['sex_left'])
df4=df3[df3.index.isin(df1.index)].iloc[:,-3::]

Результат

enter image description here

Вы не очень разбираетесь в конфликтах, поэтому я предположил конфликты по Имени и Возрасту. По этой причине я явно отбрасываю NaN по возрасту, потому что они существуют там, где я их не заполнял

df3=df3.dropna(subset=['age','age_left'])

Получение фрейма данных на серии логического выбора

df3[(df3['name_left']!=df3['name'])& df3['age_left']!=df3['age']].dropna(thresh=1, inplace=True)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...