some_dict = {'a': [1,2,3,4], 'b': [5,6,7,8],}
df = pd.DataFrame(some_dict)
mask1 = pd.Series([False, True, False, True])
df['c'] = df.loc[mask1, 'a']
Это создаст новый столбец c
со значениями NaN, где mask1
— это False
, и значениями из столбца a
, где mask1
— это True
. Теперь я добавляю b
к c
, при другом условии
mask2 = pd.Series([True, False, False, False])
df['c'] += df.loc[mask2, 'b']
Однако это поместит ВСЕ значения в NaN. Я предполагаю, что это потому, что NaN + 0
и 0 + NaN
равны NaN
. Я попытался решить это, написав
df['c'] = df.loc[mask1, 'a'].fillna(0)
df['c'] = df.loc[mask2, 'b'].fillna(0)
Почему замена NaN
на 0
через fillna()
не работает?
@armara - then just add nothing.
- и ничего в pandas
нет NaN
;) Думаю, вам нужно добавить 0
?
да, я не имел в виду добавить NaN
, я не имел в виду ничего не добавлять, как в 0
Старайтесь всегда сопоставлять индекс lvalue с индексом rvalue. В противном случае pandas делает все возможное, чтобы переиндексировать их перед выполнением вашей операции. Смотрите мой ответ для краткого и правильного способа сделать это.
Если проверить, как это работает, пропущенные значения добавляются только для несовпадающих строк - Ложное значение в маске:
print (df.loc[mask1, 'a'])
1 2
3 4
Name: a, dtype: int64
Поэтому, если вы хотите заменить NaN, пропущенных значений нет, поэтому это невозможно:
print (df.loc[mask1, 'a'].fillna(0))
1 2
3 4
Name: a, dtype: int64
Если назначить столбец, то также должны быть созданы несоответствующие значения - и потому что панды понятия не имеют, что должно быть создано NaN
s:
df['c'] = df.loc[mask1, 'a']
print (df)
a b c
0 1 5 NaN <- False
1 2 6 2.0
2 3 7 NaN <- False
3 4 8 4.0
Поэтому, если нужно заменить NaN на 0
, нужно numpy.where - если True
s передается значения из a
, если False
передается 0
:
df['c'] = np.where(mask1, df['a'], 0)
print (df)
a b c
0 1 5 0
1 2 6 2
2 3 7 0
3 4 8 4
Еще одна альтернатива пандам — Series.where:
df['c'] = df['a'].where(mask1, 0)
print (df)
a b c
0 1 5 0
1 2 6 2
2 3 7 0
3 4 8 4
Все вместе:
some_dict = {'a': [1,2,3,4], 'b': [5,6,7,8],}
df = pd.DataFrame(some_dict)
mask1 = pd.Series([False, True, False, True])
df['c'] = np.where(mask1, df['a'], 0)
mask2 = pd.Series([True, False, False, False])
df['c'] += np.where(mask2, df['b'], 0)
print (df)
a b c
0 1 5 5
1 2 6 2
2 3 7 0
3 4 8 4
Другая идея — использовать Series.add с fill_value=0
:
some_dict = {'a': [1,2,3,4], 'b': [5,6,7,8],}
df = pd.DataFrame(some_dict)
mask1 = pd.Series([False, True, False, True])
df['c'] = df.loc[mask1, 'a']
print (df)
a b c
0 1 5 NaN
1 2 6 2.0
2 3 7 NaN
3 4 8 4.0
mask2 = pd.Series([True, False, False, False])
df['c'] = df['c'].add(df.loc[mask2, 'b'], fill_value=0)
print (df)
a b c
0 1 5 5.0
1 2 6 2.0
2 3 7 NaN
3 4 8 4.0
СПАСИБО! :D np.where
волшебно, разве в пандах нет эквивалентной функции?
@armara - Вы можете использовать df['c'] = df['a'].where(mask1, 0)
. Кстати, если нужно + NaN
значения нужны .add
, добавлено в конец ответа.
@armara конечно: df.where
@PierreD - Или вот Series.where - обработка одного столбца
Старайтесь всегда сопоставлять индекс lvalue с индексом rvalue. В противном случае pandas делает все возможное, чтобы переиндексировать их перед выполнением вашей операции.
Кроме того, всегда явно устанавливайте для нового столбца какое-либо значение по умолчанию по вашему выбору, например. 0, прежде чем выполнять задания на шаг (это также даст вам правильное dtype
).
Итак, конкретно:
some_dict = {'a': [1,2,3,4], 'b': [5,6,7,8],}
df = pd.DataFrame(some_dict)
mask1 = pd.Series([False, True, False, True])
df['c'] = 0
df.loc[mask1, 'c'] = df.loc[mask1, 'a']
mask2 = pd.Series([True, False, False, False])
df.loc[mask2, 'c'] += df.loc[mask2, 'b']
print(df)
a b c
0 1 5 5
1 2 6 2
2 3 7 0
3 4 8 4
Я ожидал добавить значения из столбцов
b
в столбецc
, но только там, гдеmask2
верно. А если этоFalse
, то просто ничего не добавляйте.