Подтвердить что ты не робот

Замените недопустимые значения 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, для вашей информации.

4b9b3361

Ответ 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() распознает их как недействительные.