У вас есть четыре основных варианта преобразования типов в пандах:
-
to_numeric()
- предоставляет функциональные возможности для безопасного преобразования нечисловых типов (например, строк) в подходящий числовой тип. (См. Также to_datetime()
и to_timedelta()
.)
-
astype()
- преобразовать (почти) любой тип в (почти) любой другой тип (даже если это не обязательно разумно). Также позволяет преобразовывать в категориальные типы (очень полезно).
-
infer_objects()
- служебный метод для преобразования столбцов объектов, содержащих объекты Python, в тип pandas, если это возможно.
-
convert_dtypes()
- преобразовать столбцы DataFrame в «наилучший из возможных» dtype, который поддерживает pd.NA
(объект pandas для указания отсутствующего значения).
Прочтите более подробные объяснения и использование каждого из этих методов.
1. to_numeric()
Лучший способ преобразовать один или несколько столбцов DataFrame в числовые значения - использовать pandas.to_numeric()
.
Эта функция попытается преобразовать нечисловые объекты (например, строки) в целые числа или числа с плавающей запятой в зависимости от ситуации.
Базовое использование
Входными данными для to_numeric()
является серия или отдельный столбец DataFrame.
>>> s = pd.Series(["8", 6, "7.5", 3, "0.9"]) # mixed string and numeric values
>>> s
0 8
1 6
2 7.5
3 3
4 0.9
dtype: object
>>> pd.to_numeric(s) # convert everything to float values
0 8.0
1 6.0
2 7.5
3 3.0
4 0.9
dtype: float64
Как видите, возвращается новая серия. Не забудьте присвоить этот вывод имени переменной или столбца, чтобы продолжить его использование:
# convert Series
my_series = pd.to_numeric(my_series)
# convert column "a" of a DataFrame
df["a"] = pd.to_numeric(df["a"])
Вы также можете использовать его для преобразования нескольких столбцов DataFrame с помощью метода apply()
:
# convert all columns of DataFrame
df = df.apply(pd.to_numeric) # convert all columns of DataFrame
# convert just columns "a" and "b"
df[["a", "b"]] = df[["a", "b"]].apply(pd.to_numeric)
Если все ваши значения могут быть преобразованы, это, вероятно, все, что вам нужно.
Обработка ошибок
Но что, если некоторые значения не могут быть преобразованы в числовой тип?
to_numeric()
также принимает аргумент ключевого слова errors
, который позволяет заставить нечисловые значения быть NaN
или просто игнорировать столбцы, содержащие эти значения.
Вот пример использования серии строк s
с объектом dtype:
>>> s = pd.Series(['1', '2', '4.7', 'pandas', '10'])
>>> s
0 1
1 2
2 4.7
3 pandas
4 10
dtype: object
Поведение по умолчанию - поднять, если не удается преобразовать значение. В этом случае он не может справиться со строкой pandas:
>>> pd.to_numeric(s) # or pd.to_numeric(s, errors='raise')
ValueError: Unable to parse string
Вместо того, чтобы потерпеть неудачу, мы могли бы захотеть, чтобы «панды» считались отсутствующим / неверным числовым значением. Мы можем привести недопустимые значения к NaN
следующим образом, используя аргумент ключевого слова errors
:
>>> pd.to_numeric(s, errors='coerce')
0 1.0
1 2.0
2 4.7
3 NaN
4 10.0
dtype: float64
Третий вариант для errors
- просто игнорировать операцию, если обнаружено недопустимое значение:
>>> pd.to_numeric(s, errors='ignore')
# the original Series is returned untouched
Этот последний вариант особенно полезен для преобразования всего вашего DataFrame, но мы не знаем, какие из наших столбцов можно надежно преобразовать в числовой тип. В этом случае просто напишите:
df.apply(pd.to_numeric, errors='ignore')
Функция будет применена к каждому столбцу DataFrame. Столбцы, которые можно преобразовать в числовой тип, будут преобразованы, а столбцы, которые не могут быть преобразованы (например, они содержат нецифровые строки или даты), останутся без изменений.
Понижающее преобразование
По умолчанию преобразование с to_numeric()
даст вам либо int64
, либо float64
dtype (или любое другое целое число, присущее вашей платформе).
Обычно это то, что вам нужно, но что, если вы хотите сэкономить немного памяти и использовать более компактный тип dtype, например float32
или int8
?
to_numeric()
дает вам возможность понижать значение до 'integer'
, 'signed'
, 'unsigned'
, 'float'
. Вот пример простой серии s
целочисленного типа:
>>> s = pd.Series([1, 2, -7])
>>> s
0 1
1 2
2 -7
dtype: int64
При понижении до 'integer'
используется наименьшее возможное целое число, которое может содержать значения:
>>> pd.to_numeric(s, downcast='integer')
0 1
1 2
2 -7
dtype: int8
При понижении до 'float'
аналогично выбирается плавающий тип меньшего размера, чем обычно:
>>> pd.to_numeric(s, downcast='float')
0 1.0
1 2.0
2 -7.0
dtype: float32
2. astype()
Метод astype()
позволяет явно указать тип dtype, который должен иметь ваш DataFrame или Series. Он очень универсален, так как вы можете попробовать перейти от одного типа к другому.
Базовое использование
Просто выберите тип: вы можете использовать dtype NumPy (например, np.int16
), некоторые типы Python (например, bool) или типы, специфичные для pandas (например, категориальный dtype).
Вызовите метод объекта, который вы хотите преобразовать, и astype()
попытается преобразовать его за вас:
# convert all DataFrame columns to the int64 dtype
df = df.astype(int)
# convert column "a" to int64 dtype and "b" to complex type
df = df.astype({"a": int, "b": complex})
# convert Series to float16 type
s = s.astype(np.float16)
# convert Series to Python strings
s = s.astype(str)
# convert Series to categorical type - see docs for more details
s = s.astype('category')
Обратите внимание, я сказал «попробуйте» - если astype()
не знает, как преобразовать значение в Series или DataFrame, это вызовет ошибку. Например, если у вас есть значение NaN
или inf
, вы получите сообщение об ошибке при попытке преобразовать его в целое число.
Начиная с pandas 0.20.0, эту ошибку можно подавить, передав errors='ignore'
. Ваш исходный объект будет возвращен нетронутым.
Будьте осторожны
astype()
- мощный инструмент, но иногда он может преобразовывать значения «неправильно». Например:
>>> s = pd.Series([1, 2, -7])
>>> s
0 1
1 2
2 -7
dtype: int64
Это небольшие целые числа, как насчет преобразования в 8-битный тип без знака для экономии памяти?
>>> s.astype(np.uint8)
0 1
1 2
2 249
dtype: uint8
Преобразование сработало, но -7 было преобразовано в 249 (т.е. 2 8 - 7)!
Попытка выполнить понижающее преобразование с помощью pd.to_numeric(s, downcast='unsigned')
вместо этого может помочь предотвратить эту ошибку.
3. infer_objects()
Версия 0.21.0 pandas представила метод infer_objects()
для преобразования столбцов DataFrame с типом данных объекта в более конкретный тип (мягкие преобразования).
Например, вот DataFrame с двумя столбцами типа объекта. Один содержит фактические целые числа, а другой - строки, представляющие целые числа:
>>> df = pd.DataFrame({'a': [7, 1, 5], 'b': ['3','2','1']}, dtype='object')
>>> df.dtypes
a object
b object
dtype: object
Используя infer_objects()
, вы можете изменить тип столбца 'a' на int64:
>>> df = df.infer_objects()
>>> df.dtypes
a int64
b object
dtype: object
Столбец «b» остался один, поскольку его значения были строками, а не целыми числами. Если вы хотите принудительно преобразовать оба столбца в целочисленный тип, вы можете использовать вместо него df.astype(int)
.
4. convert_dtypes()
Версия 1.0 и выше включает метод convert_dtypes()
для преобразования столбцов Series и DataFrame в наилучший из возможных dtype, который поддерживает отсутствующее значение pd.NA
.
Здесь «наилучший из возможных» означает тип, наиболее подходящий для хранения значений. Например, это целочисленный тип pandas, если все значения являются целыми числами (или отсутствующими значениями): столбец объекта целочисленных объектов Python преобразуется в Int64
, столбец значений NumPy int32
станет pandas dtype Int32
.
С нашим object
DataFrame df
мы получаем следующий результат:
>>> df.convert_dtypes().dtypes
a Int64
b string
dtype: object
Поскольку столбец 'a' содержал целочисленные значения, он был преобразован в тип Int64
(который может содержать отсутствующие значения, в отличие от int64
).
Столбец 'b' содержал строковые объекты, поэтому был изменен на pandas 'string
dtype.
По умолчанию этот метод определяет тип на основе значений объекта в каждом столбце. Мы можем изменить это, передав infer_objects=False
:
>>> df.convert_dtypes(infer_objects=False).dtypes
a object
b string
dtype: object
Теперь столбец 'a' остался столбцом объекта: pandas знает, что его можно описать как 'целочисленный' столбец (внутри он выполнялся infer_dtype
), но не понял, какой именно тип целого числа он должен был так не преобразовал. Столбец 'b' снова был преобразован в 'строковый' dtype, поскольку он был распознан как содержащий 'строковые' значения.
Кроме того, в отличие от .astype (float), это преобразует строки в NaN вместо того, чтобы вызывать ошибку.
.convert_objects
устарел, так как0.17
- используйте вместо негоdf.to_numeric
есть ли способ
error=coerce
вastype()
?