#python #pandas
#python #pandas
Вопрос:
Я пытаюсь объединить повторяющиеся столбцы в моем фрейме данных. Мой фрейм данных многоиндексирован и выглядит как
sex_COPYL sex_COPYR age_COPYL age_COPYR
ID Date
A 2010-01-01 NaN F NaN 230
B 2010-01-01 NaN F NaN 487
2010-02-01 NaN M NaN 488
C 2010-01-01 NaN M NaN 534
D 2012-09-08 M NaN 432 NaN
Я ожидаю, что фрейм данных будет выглядеть следующим образом
sex age
ID Date
A 2010-01-01 F 230
B 2010-01-01 F 487
2010-02-01 M 488
C 2010-01-01 M 534
D 2012-09-08 M 432
Я пытаюсь добиться этого с помощью
df.groupby(df.columns.map(lambda x: x.split('_COPY')[0], 1)).apply(lambda x: x.mode(1)[0])
но я получаю сообщение об ошибке
ValueError: Grouper and axis must be same length
Другие сообщения, касающиеся этой ошибки, показывают, что у пользователя не было столбца, по которому они пытались сгруппировать. Является ли моя ошибка результатом повторяющихся удаленных имен, и если да, то как мне это исправить?
Комментарии:
1. Что мешает вам просто удалить столбец? Я предполагаю, что столбец не обязательно будет all
nan
. Будут ли конфликтующие данные? Например,M
в одном столбце иF
в другом? Или разного возраста? Как это следует решить? Или это всегда одно значение иnan
?2. @busybear Это хороший момент, и это предположение верно. Всегда есть одно значение и
nan
. Я отредактирую свой вопрос, чтобы отразить это, спасибо, что указали на это!3. Привет, nebula, print(df.columns) относится к классу «<class’pandas.core.indexes.base. Индекс’>». итак, если вы используете df.groupby(df.columns), это выдаст ошибку, как вы указали выше. для работы вы должны использовать df.groupby(список (df.columns)).
4. Привет @BhanuTez, но я не группирую по полным именам столбцов, я группирую по
df.columns.map(...)
, что похоже на группировку по['sex', 'sex', 'age', 'age']
.5. @HS-nebula Я говорю о причине «ValueError». Но в любом случае в вашем коде также есть проблема с именем столбца.
Ответ №1:
в groupby отсутствует axis= 1:
df.groupby(df.columns.map(lambda x: x.split('_COPY')[0], 1), axis=1).apply(lambda x: x.mode(1)[0])
альтернативное решение (без groupby, но аналогично со stack и unstack):
df.rename(columns=lambda x: x.split('_COPY')[0]).stack().unstack()
метод stack удаляет значения na по умолчанию
Комментарии:
1. Спасибо, я понял, что у меня была опечатка в строке groupby, поэтому в
1
моемmap
коде не должно быть a. Кроме того, хорошее альтернативное решение.
Ответ №2:
Альтернативное решение:
# use both bfill and ffill to handle NaNs on both
# left and right of valid values
df['sex'] = (df.filter(like='sex')
.bfill(axis=1)
.ffill(axis=1)
.iloc[:, 0])
df['age'] = (df.filter(like='age')
.bfill(axis=1)
.ffill(axis=1)
.iloc[:, 0]
.astype(int))
df = df[['sex', 'age']]
df
sex age
ID Date
A 2010-01-01 F 230
B 2010-01-01 F 487
2010-02-01 M 488
C 2010-01-01 M 534
D 2012-09-08 M 432
Комментарии:
1. Спасибо, этот метод работает, но он не объясняет, почему
groupby
не удалось выполнить то же самое без создания дополнительных столбцов.2. В качестве бонуса я мог бы сделать это в одной строке, например
df.bfill(axis=1).ffill(axis=1).iloc[:, ::2]
, а затем переименовать столбцы.
Ответ №3:
Сначала мы можем преобразовать имена столбцов:
df.columns = [c.split('_COPY')[0] for c in df.columns]
df
Out:
sex sex age age
ID Date
A 2010-01-01 NaN F NaN 230
B 2010-01-01 NaN F NaN 487
NaN 2010-02-01 NaN M NaN 488
C 2010-01-01 NaN M NaN 534
D 2012-09-08 NaN M NaN 432
Затем группируйте по именам столбцов и режиму использования:
df.groupby(axis=1, level=0).agg(lambda x: x.mode(axis=1)[0])
Out:
age sex
ID Date
A 2010-01-01 230.0 F
B 2010-01-01 487.0 F
NaN 2010-02-01 488.0 M
C 2010-01-01 534.0 M
D 2012-09-08 432.0 M
Обновление: оригинальная однострочная версия также работает с axis=1
добавленными в список groupby
параметрами (поскольку мы группируем по столбцам, а не по строкам):
df.groupby(df.columns.map(lambda x: x.split('_COPY')[0], 1), axis=1).apply(lambda x: x.mode(1)[0])
Комментарии:
1. Итак, все, что мне нужно было сделать, это добавить
level=0
в мойgroupby
? Можете ли вы объяснить, почему?2. Проблема, похоже, в том, что в вашем заявлении отсутствует
axis=1
(поскольку нам нужно группировать по столбцам, а не по строкам) в качестве параметра groupby. Хорошо работает следующее:df.groupby(df.columns.map(lambda x: x.split('_COPY')[0], 1), axis=1).apply(lambda x: x.mode(1)[0])