Как удалить дубликаты столбцов в Pandas DataFrame

import pandas as pd
import numpy as np

Как удалить дубликаты столбцов? Есть DataFrame, в котором столбцы под индексами 0, 1, 2 имеют одинаковые данные Как в такой ситуации получить чистый DataFrame?


Ответы (3 шт):

Автор решения: Алексей Р

Воспользуйтесь методом .first_valid_index(). Фрейм разделяем через индекс по колонкам -2, т.е. считаем, что 2 правые колонки - это числа, а все начальные колонки - текст.

import pandas as pd
import numpy as np

df = pd.DataFrame({0: [np.nan, np.nan, np.nan, 'coconut', np.nan, 'walnut', np.nan, np.nan, np.nan, 'apricot'],
                   1: [np.nan, np.nan, 'peach', 'coconut', np.nan, 'walnut', 'pineapple', np.nan, np.nan, 'apricot'],
                   2: ['pear', 'strawberry', 'peach', 'coconut', np.nan, 'walnut', 'pineapple', 'grape', np.nan, 'apricot'],
                   3: [1, 2, 3, 4, np.nan, 12, 7, 11, np.nan, 14],
                   4: [10, 20, 30, 40, np.nan, 15, 9, 22, np.nan, 13]})
df = pd.concat([df.iloc[:, :-2].apply(lambda x: x[idx] if (idx := x.first_valid_index()) is not None else np.nan, axis=1), df.iloc[:, -2:]], axis=1).rename(columns={3: 1, 4: 2})
print(df)
            0     1     2
0        pear   1.0  10.0
1  strawberry   2.0  20.0
2       peach   3.0  30.0
3     coconut   4.0  40.0
4         NaN   NaN   NaN
5      walnut  12.0  15.0
6   pineapple   7.0   9.0
7       grape  11.0  22.0
8         NaN   NaN   NaN
9     apricot  14.0  13.0

Еще вариант без .apply()

df = pd.concat([df.iloc[:, :-2].stack().groupby(level=0).first(), df.iloc[:, -2:]], axis=1).sort_index()
→ Ссылка
Автор решения: CrazyElf

Пример у вас не очень валидный, у вас нет варианта, чтобы колонка 2 не покрывала все ваши потребности. Но могу предложить такой вариант для объединения данных трёх первых колонок обратно во вторую колонку. Потом остальные колонки можно отбросить:

df.iloc[:, 2] = df.iloc[:,:3].apply(lambda x: next(iter(set(x.dropna()) or set([np.NaN]))), axis=1)
df = df.iloc[:, 2:]

Пояснения:

  • df.iloc[:,:3] - взять первые три колонки
  • apply(lambda x: ..., axis=1) - применить к ним построчно функцию
  • next - взять первое значение из последовательности
  • iter - перебрать (множество)
  • set(x.dropna()) - выкинуть NA и схлопнуть одинаковые значения в одно
  • or set([np.NaN]) - если получилось пустое множество, сделать множество из одного элемента NA
→ Ссылка
Автор решения: strawdog

Если вы не знаете, сколько у вас колонок может быть с неполными данными, то можно воспользоваться советом от @CrazyElf и выбрать колонки по типу данных:

obj_cols = df.select_dtypes(include='object')

а затем:

df["res"] = obj_cols.apply(lambda x: pd.Series(x.dropna().values), axis=1)[0]
df = df.drop(columns=obj_cols.columns)

df:

      3     4         res
0   1.0  10.0        pear
1   2.0  20.0  strawberry
2   3.0  30.0       peach
3   4.0  40.0     coconut
4   NaN   NaN         NaN
5  12.0  15.0      walnut
6   7.0   9.0   pineapple
7  11.0  22.0       grape
8   NaN   NaN         NaN
9  14.0  13.0     apricot
→ Ссылка