У меня есть таблица:
Я хочу создать новый столбец D, который должен объединять столбцы B и C, если один из столбцов пуст (NA):
Если оба столбца содержат значение, он должен вернуть текст «ошибка» внутри ячейки.
Спасибо, я добавил, что текст ошибки должен быть значением ячейки.
Есть несколько способов добиться этого.
Использование 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
, в которой присутствуют оба значения, поскольку это сделало бы весь столбец D
object
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
Пожалуйста, точно укажите желаемое поведение, когда присутствуют оба значения. Когда вы говорите «ошибка», вы хотите, чтобы все вычисления прервались (сбой), или вы хотите поместить значение, указывающее на то, что оно недействительно в col. Д?