Панды объединяют два, если один пуст

У меня есть таблица:

А Б С Икс 1 нет данных у нет данных 4 г 2 нет данных п нет данных 5 т 6 7

Я хочу создать новый столбец D, который должен объединять столбцы B и C, если один из столбцов пуст (NA):

А Б С Д Икс 1 нет данных 1 у нет данных 4 4 г 2 нет данных 2 п нет данных 5 5 т 6 7 ошибка

Если оба столбца содержат значение, он должен вернуть текст «ошибка» внутри ячейки.

Пожалуйста, точно укажите желаемое поведение, когда присутствуют оба значения. Когда вы говорите «ошибка», вы хотите, чтобы все вычисления прервались (сбой), или вы хотите поместить значение, указывающее на то, что оно недействительно в col. Д?

Dev-iL 20.02.2023 08:58

Спасибо, я добавил, что текст ошибки должен быть значением ячейки.

honeymoon 20.02.2023 09:07
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
2
71
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Есть несколько способов добиться этого.

Использование fillna и маски

df['D'] = df['B'].fillna(df['C']).mask(df['B'].notna()&df['C'].notna(), 'error')

Или numpy.select:

m1 = df['B'].notna()
m2 = df['C'].notna()
df['D'] = np.select([m1&m2, m1], ['error', df['B']], df['C'])

Выход:

   A    B    C      D
0  x  1.0  NaN    1.0
1  y  NaN  4.0    4.0
2  z  2.0  NaN    2.0
3  p  NaN  5.0    5.0
4  t  6.0  7.0  error

Вы можете сначала рассчитать маску со строками, в которых присутствуют оба значения, а затем заполнить NA значениями, скажем, столбца B, значениями из столбца C. Используя маску, рассчитанную на первом шаге, просто присвойте значения NA там, где это необходимо.

error_mask = df['B'].notna() & df['C'].notna()
df['D'] = df['B'].fillna(df['C'])
df.loc[error_mask, 'D'] = pd.NA
df

   A     B     C     D
0  x     1  <NA>     1
1  y  <NA>     4     4
2  z     2  <NA>     2
3  p     3     5  <NA>


OR
df = df['D'].astype(str)
df.loc[error_mask, 'D'] = 'error'

Я бы посоветовал не назначать строку error, в которой присутствуют оба значения, поскольку это сделало бы весь столбец Dobject dtype

В дополнение к предыдущему ответу вы можете решить эту проблему с помощью ряда .apply() методов в сочетании с lambda функциями.

Рассмотрим представленный вами фрейм данных с np.nan в качестве значений NA:

df = pd.DataFrame({
    'B':[1, np.nan, 2, np.nan, 6], 
    'C':[np.nan, 4, np.nan, 5, 7]})

Сначала создайте список элементов из рассматриваемой серии:

df['D'] = df.apply(lambda x: list(x), axis=1) 

Это даст вам pd.Series список значений в виде элементов, например. [1.0, nan] для первого ряда. Затем удалите все np.nan элементы, используя этот np.nan != np.nan в numpy (см. также ответ здесь: Как я могу удалить Nan из списка Python/NumPy)

df['E'] = df['D'].apply(lambda x: [i for i in x if i == i])

Наконец, создайте error, отфильтровав по длине.

df['F'] =  df['E'].apply(lambda x: x[0] if len(x) == 1 else 'error')

Результирующий фрейм данных работает следующим образом:

    B   C   D   E   F
0   1.0 NaN [1.0, nan]  [1.0]   1.0
1   NaN 4.0 [nan, 4.0]  [4.0]   4.0
2   2.0 NaN [2.0, nan]  [2.0]   2.0
3   NaN 5.0 [nan, 5.0]  [5.0]   5.0
4   6.0 7.0 [6.0, 7.0]  [6.0, 7.0]  error

Конечно, вы можете связать все это вместе в не очень питоническом, но однострочном ответе: a = df.apply(lambda x: list(x), axis=1).apply(lambda x: [i for i in x if i == i]).apply(lambda x: x[0] if len(x) == 1 else 'error')

Взгляните на функцию comb_first:

df['C'].combine_first(df['B']).mask(df['B'].notna() & df['C'].notna(), 'error')

Выход:

0      1.0
1      4.0
2      2.0
3      5.0
4    error
Name: C, dtype: object

Другие вопросы по теме