Изменение отфильтрованных (selected) значений в DataFrame Pandas

Иногда возникает ситуация, когда нужно отфильтровать с помощью некоторого логического выражения, записи в Pandas DataFrame и затем изменить их. Казалось бы, нет ничего проще:

#nc - Pandas DataFrame with DateTime as index
#GBPUSD and Data - is a column in the nc
nc[((nc.Date >= start_date) & (nc.Date <= end_date))]['GBPUSD'] = 10
print(nc)

Но print(nc) показывает, что значения не изменились, а Python выдает предупреждение:

SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

Почему возникла ошибка? При выполнении первой части выражения:

nc[((nc.Date >= start_date) & (nc.Date <= end_date))]

создалась копия, а вторая операция, устанавливающая значение выражения, меняла значение уже в копии, соответственно, на исходном DataFrame изменения не отразились.

Нужно избавиться от двух последовательных операций, и делается это атомарной операцией:

nc.loc[((nc.Date >= start_date) & (nc.Date <= end_date)), 'GBPUSD'] = 10
print(nc)

В этом случае гарантированно меняется значение в исходном view, а не на копии, и предупреждение пропадает. Можно использовать другой вариант записи, но он менее надежен:

nc.GBPUSD[((nc.Date >= start_date) & (nc.Date <= end_date))] = 10
print(nc)

В данном случае результат такой же, но снова появляется предупреждение, поскольку такой код не гарантирует, что изменения выполнены на оригинале, а не на копии.

Можно сделать изменения в оригинале, используя индексы отфильтрованных записей:

#nc.index = np.arange(nc.shape[0])
indexes = nc[(nc.Date >= start_date) & (nc.Date <= end_date)].index
nc.at[indexes, 'GBPUSD'] = 10
print(nc)

Сначала получаем индексы отфильтрованных значений, а затем используем

nc.at[indexes, 'GBPUSD'] = 10

для изменения значения в колонке ‘GBPUSD’ по списку индексов.

Полезные ссылки

Spread the love
Запись опубликована в рубрике IT рецепты с метками , . Добавьте в закладки постоянную ссылку.

Обсуждение закрыто.