#python #pandas #method-chaining
#python #панды #метод-цепочка
Вопрос:
Я не могу понять, как установить значение ряда по определенному индексу в цепочечном стиле.
Например, скажем, у меня есть следующий фрейм данных:
>>> df = pd.DataFrame({'a': [1,2,3], 'b': [0,0,0]})
>>> df
a b
0 1 0
1 2 0
2 3 0
Если я хочу изменить все значения столбца в конвейере, я могу использовать pandas.DataFrame.assign()
:
>>> df.assign(b=[4,5,6])
a b
0 1 4
1 2 5
2 3 6
… и тогда я могу делать другие вещи с фреймом данных в той же строке, например:
>>> df.assign(b=[4,5,6]).mul(100)
a b
0 100 400
1 200 500
2 300 600
Но я не могу сделать это для отдельного значения в определенном в серии.
>>> s = df['a']
>>> s
0 1
1 2
2 3
Name: a, dtype: int64
Я могу, конечно, просто использовать обычную операцию присваивания Python, используя =
:
>>> s[1] = 9
>>> s
0 1
1 9
2 3
Name: a, dtype: int64
Но проблемы с этим заключаются в:
- Он на месте, поэтому он изменяет мой существующий фрейм данных
- Использование операторов присваивания
=
не допускается в лямбда-функциях Python
Например, что, если бы я хотел сделать это:
>>> df.apply(lambda x: x['b', 0] = 13, axis=1)
File "<stdin>", line 1
df.apply(lambda x: x['b', 0] = 13, axis=1)
^
SyntaxError: expression cannot contain assignment, perhaps you meant "=="?
(Я понимаю, что есть лучшие способы для этого конкретного случая, но это всего лишь выдуманный пример.)
Как я могу установить значение по указанному индексу ряда?Я хотел бы иметь возможность просто использовать что-то вроде s.set_value(idx, 'my_val')
и вернуть измененную (скопированную) серию.
Комментарии:
1. Не самый лучший, но
apply
занимает ряд, поэтому у вас естьname
иindex
:df.apply(lambda x: np.where(x.index==0, 13, x) if x.name=='b' else x)
2. Круто, это долго для такой простой задачи, но это действительно работает.
Ответ №1:
Вы можете использовать pandas.Series.where()
для возврата копии столбца с элементом по указанному индексу.
Это в основном похоже на использование .loc
:
>>> df['b'].where(df['b'].index != 1, 13)
0 0
1 13
2 0
Name: b, dtype: int64
Если у вас есть индекс, который не является a RangeIndex
или который не начинается с нуля, вы можете вызвать reset_index()
before where()
, который будет похож на приведенный выше .loc
, только имитируя поведение .iloc
instead:
>>> s = pd.Series({'a': 0, None: 0, True: 0})
>>> s
a 0
NaN 0
True 0
dtype: int64
>>> s.where(s.reset_index().index != 1, 13)
a 0
NaN 13
True 0
dtype: int64