Замените недопустимые значения None в Pandas DataFrame
Есть ли способ заменить значения на None
в Pandas в Python?
Вы можете использовать df.replace('pre', 'post')
и можете заменить значение другим, но этого нельзя сделать, если вы хотите заменить значением None
, что при попытке получить странный результат.
Итак, вот пример:
df = DataFrame(['-',3,2,5,1,-5,-1,'-',9])
df.replace('-', 0)
который возвращает успешный результат.
Но,
df.replace('-', None)
который возвращает следующий результат:
0
0 - // this isn't replaced
1 3
2 2
3 5
4 1
5 -5
6 -1
7 -1 // this is changed to '-1'...
8 9
Почему такой странный результат возвращается?
Поскольку я хочу добавить этот фрейм данных в базу данных MySQL, я не могу поместить значения NaN
ни в один элемент моего фрейма данных и вместо этого хочу добавить None
. Конечно, вы можете сначала изменить '-'
на NaN
а затем преобразовать NaN
в None
, но я хочу знать, почему фрейм данных работает таким ужасным образом.
Протестировано на пандах 0.12.0 dev на Python 2.7 и OS X 10.8. Python - это предустановленная версия для OS X, и я установил pandas, используя скрипт SciPy Superpack, для вашей информации.
Ответы
Ответ 1
Собственно в более поздних версиях pandas это даст TypeError:
df.replace('-', None)
TypeError: If "to_replace" and "value" are both None then regex must be a mapping
Вы можете сделать это, передав список или словарь:
In [11]: df.replace('-', df.replace(['-'], [None]) # or .replace('-', {0: None})
Out[11]:
0
0 None
1 3
2 2
3 5
4 1
5 -5
6 -1
7 None
8 9
Но я рекомендую использовать NaN, а не None:
In [12]: df.replace('-', np.nan)
Out[12]:
0
0 NaN
1 3
2 2
3 5
4 1
5 -5
6 -1
7 NaN
8 9
Ответ 2
where
- это, вероятно, то, что вы ищете. Так
data=data.where(data=='-', None)
Из panda docs:
where
[возвращает] объект той же формы, что и self, и соответствующие записи которого принадлежат самому себе, где cond является True, а в противном случае - другим).
Ответ 3
Я предпочитаю решение с использованием replace
на dict
из-за его простоты и элегантности:
df.replace({'-': None})
Вы также можете иметь больше замен:
df.replace({'-': None, 'None': None})
И даже для более крупных замен всегда очевидно и ясно, что заменяется чем, что, на мой взгляд, намного сложнее для длинных списков.
Ответ 4
df = pd.DataFrame(['-',3,2,5,1,-5,-1,'-',9])
df = df.where(df!='-', None)
Ответ 5
Прежде чем приступить к этому посту, важно понять разницу между NaN и None. Один тип с плавающей запятой, другой тип объекта. Панды лучше подходят для работы со скалярными типами, так как многие методы для этих типов могут быть векторизованы. Pandas пытается последовательно обрабатывать None и NaN, но NumPy не может.
Мое предложение (и Энди) придерживаться NaN.
(v0. 24+) Лучшее решение для данных CSV/Excel: na_values=['-']
Если вы загрузили эти данные из CSV/Excel, у меня есть для вас хорошие новости. Вы можете отменить это в корне во время загрузки данных вместо того, чтобы писать исправление с кодом в качестве следующего шага.
Большинство функций pd.read_*
(таких как read_csv
и read_excel
) принимают атрибут na_values
.
file.csv
A,B
-,1
3,-
2,-
5,3
1,-2
-5,4
-1,-1
-,0
9,0
Теперь, чтобы преобразовать символы -
в NaN, сделайте,
import pandas as pd
df = pd.read_csv('file.csv', na_values=['-'])
df
A B
0 NaN 1.0
1 3.0 NaN
2 2.0 NaN
3 5.0 3.0
4 1.0 -2.0
5 -5.0 4.0
6 -1.0 -1.0
7 NaN 0.0
8 9.0 0.0
И похоже на другие функции/форматы файлов.
PS: На v0. 24+ вы можете сохранить целочисленный тип, даже если в вашем столбце есть NaN (да, поговорите о том, чтобы получить торт и съесть его тоже). Вы можете указать dtype='Int32'
df = pd.read_csv('file.csv', na_values=['-'], dtype='Int32')
df
A B
0 NaN 1
1 3 NaN
2 2 NaN
3 5 3
4 1 -2
5 -5 4
6 -1 -1
7 NaN 0
8 9 0
df.dtypes
A Int32
B Int32
dtype: object
Тип dtype - это не обычный тип int, а скорее Nullable Integer Type. Есть другие варианты.
Обработка числовых данных: pd.to_numeric
с errors='coerce
Если вы имеете дело с числовыми данными, более быстрое решение - использовать pd.to_numeric
с аргументом errors='coerce'
, который приводит недействительные значения (значения, которые не могут быть преобразованы в числовые) к NaN.
pd.to_numeric(df['A'], errors='coerce')
0 NaN
1 3.0
2 2.0
3 5.0
4 1.0
5 -5.0
6 -1.0
7 NaN
8 9.0
Name: A, dtype: float64
Чтобы сохранить (обнуляемое) целое число dtype, используйте
pd.to_numeric(df['A'], errors='coerce').astype('Int32')
0 NaN
1 3
2 2
3 5
4 1
5 -5
6 -1
7 NaN
8 9
Name: A, dtype: Int32
Чтобы привести несколько столбцов, используйте apply
:
df[['A', 'B']].apply(pd.to_numeric, errors='coerce').astype('Int32')
A B
0 NaN 1
1 3 NaN
2 2 NaN
3 5 3
4 1 -2
5 -5 4
6 -1 -1
7 NaN 0
8 9 0
... и присвоить результат обратно после.
Более подробную информацию можно найти в этом ответе.
Ответ 6
Установка нулевых значений может быть выполнена с помощью np.nan
:
import numpy as np
df.replace('-', np.nan)
Преимущество заключается в том, что df.last_valid_index()
распознает их как недействительные.