我从列表列表中创建了一个DataFrame:

table = [
    ['a',  '1.2',  '4.2' ],
    ['b',  '70',   '0.03'],
    ['x',  '5',    '0'   ],
]

df = pd.DataFrame(table)

如何将列转换为特定类型?在本例中,我想将列2和列3转换为浮点数。

是否有一种方法可以在转换到DataFrame时指定类型?还是先创建DataFrame,然后循环遍历列以更改每列的类型更好?理想情况下,我希望以动态的方式进行此操作,因为可能有数百个列,而我不想确切地指定哪些列属于哪种类型。我所能保证的是每一列都包含相同类型的值。


当前回答

在pandas中转换类型有四个主要选项:

To_numeric() -提供将非数字类型(例如字符串)安全转换为合适的数字类型的功能。(请参见to_datetime()和to_timedelta()。) Astype() -将(几乎)任何类型转换为(几乎)任何其他类型(即使这样做并不一定合理)。还允许您转换为类别类型(非常有用)。 infer_objects()——一个实用程序方法,在可能的情况下将包含Python对象的对象列转换为pandas类型。 convert_dtypes() -将DataFrame列转换为支持pd的“最佳”dtype。NA(熊猫的对象,表示一个缺失的值)。

请继续阅读以获得这些方法的更详细的解释和用法。


1. to_numeric ()

将DataFrame的一个或多个列转换为数值的最好方法是使用pandas.to_numeric()。

此函数将尝试将非数值对象(例如字符串)更改为适当的整数或浮点数。

基本用法

to_numeric()的输入是一个Series或一个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

如您所见,返回了一个新的Series。请记住将此输出分配给变量或列名以继续使用它:

# convert Series
my_series = pd.to_numeric(my_series)

# convert column "a" of a DataFrame
df["a"] = pd.to_numeric(df["a"])

你也可以使用apply()方法来转换一个DataFrame的多个列:

# 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,或者直接忽略包含这些值的列。

下面是一个使用对象为dtype的string序列的例子:

>>> 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

我们可能希望'pandas'被认为是一个缺失/错误的数值,而不是失败。我们可以使用errors关键字参数将无效值强制为NaN,如下所示:

>>> pd.to_numeric(s, errors='coerce')
0     1.0
1     2.0
2     4.7
3     NaN
4    10.0
dtype: float64

错误的第三个选项是,如果遇到无效值,则忽略该操作:

>>> 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()方法使您能够明确您希望DataFrame或Series具有的dtype。它的用途非常广泛,你可以尝试从一种类型转换到任何其他类型。

基本用法

只需要选择一个类型:你可以使用NumPy dtype(例如np.int16),一些Python类型(例如bool),或特定于熊猫的类型(如分类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')

注意我说的是"try" -如果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(即28 -7)!

尝试使用pd向下投射。To_numeric (s, downcast='unsigned')可以帮助避免此错误。


3.infer_objects ()

pandas的0.21.0版引入了方法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列转换为支持pd的最佳dtype。NA缺失值。

这里的“最佳可能”是指最适合保存值的类型。例如,这是一个pandas整型,如果所有的值都是整数(或缺值):Python整型对象的对象列转换为Int64, NumPy int32值的列转换为pandas dtype int32。

使用我们的对象DataFrame df,我们得到以下结果:

>>> df.convert_dtypes().dtypes                                             
a     Int64
b    string
dtype: object

由于列'a'保存整数值,因此它被转换为Int64类型(与Int64不同,该类型能够保存缺失的值)。

列'b'包含字符串对象,因此被更改为pandas的字符串dtype。

默认情况下,此方法将从每列中的对象值推断类型。我们可以通过传递infer_objects=False来改变这一点:

>>> df.convert_dtypes(infer_objects=False).dtypes                          
a    object
b    string
dtype: object

现在列“a”仍然是一个对象列:pandas知道它可以被描述为一个“整数”列(在内部它运行infer_dtype),但没有确切地推断它应该有什么整数的dtype,所以没有转换它。列'b'再次被转换为'string' dtype,因为它被识别为持有'string'值。

其他回答

在pandas中转换类型有四个主要选项:

To_numeric() -提供将非数字类型(例如字符串)安全转换为合适的数字类型的功能。(请参见to_datetime()和to_timedelta()。) Astype() -将(几乎)任何类型转换为(几乎)任何其他类型(即使这样做并不一定合理)。还允许您转换为类别类型(非常有用)。 infer_objects()——一个实用程序方法,在可能的情况下将包含Python对象的对象列转换为pandas类型。 convert_dtypes() -将DataFrame列转换为支持pd的“最佳”dtype。NA(熊猫的对象,表示一个缺失的值)。

请继续阅读以获得这些方法的更详细的解释和用法。


1. to_numeric ()

将DataFrame的一个或多个列转换为数值的最好方法是使用pandas.to_numeric()。

此函数将尝试将非数值对象(例如字符串)更改为适当的整数或浮点数。

基本用法

to_numeric()的输入是一个Series或一个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

如您所见,返回了一个新的Series。请记住将此输出分配给变量或列名以继续使用它:

# convert Series
my_series = pd.to_numeric(my_series)

# convert column "a" of a DataFrame
df["a"] = pd.to_numeric(df["a"])

你也可以使用apply()方法来转换一个DataFrame的多个列:

# 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,或者直接忽略包含这些值的列。

下面是一个使用对象为dtype的string序列的例子:

>>> 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

我们可能希望'pandas'被认为是一个缺失/错误的数值,而不是失败。我们可以使用errors关键字参数将无效值强制为NaN,如下所示:

>>> pd.to_numeric(s, errors='coerce')
0     1.0
1     2.0
2     4.7
3     NaN
4    10.0
dtype: float64

错误的第三个选项是,如果遇到无效值,则忽略该操作:

>>> 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()方法使您能够明确您希望DataFrame或Series具有的dtype。它的用途非常广泛,你可以尝试从一种类型转换到任何其他类型。

基本用法

只需要选择一个类型:你可以使用NumPy dtype(例如np.int16),一些Python类型(例如bool),或特定于熊猫的类型(如分类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')

注意我说的是"try" -如果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(即28 -7)!

尝试使用pd向下投射。To_numeric (s, downcast='unsigned')可以帮助避免此错误。


3.infer_objects ()

pandas的0.21.0版引入了方法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列转换为支持pd的最佳dtype。NA缺失值。

这里的“最佳可能”是指最适合保存值的类型。例如,这是一个pandas整型,如果所有的值都是整数(或缺值):Python整型对象的对象列转换为Int64, NumPy int32值的列转换为pandas dtype int32。

使用我们的对象DataFrame df,我们得到以下结果:

>>> df.convert_dtypes().dtypes                                             
a     Int64
b    string
dtype: object

由于列'a'保存整数值,因此它被转换为Int64类型(与Int64不同,该类型能够保存缺失的值)。

列'b'包含字符串对象,因此被更改为pandas的字符串dtype。

默认情况下,此方法将从每列中的对象值推断类型。我们可以通过传递infer_objects=False来改变这一点:

>>> df.convert_dtypes(infer_objects=False).dtypes                          
a    object
b    string
dtype: object

现在列“a”仍然是一个对象列:pandas知道它可以被描述为一个“整数”列(在内部它运行infer_dtype),但没有确切地推断它应该有什么整数的dtype,所以没有转换它。列'b'再次被转换为'string' dtype,因为它被识别为持有'string'值。

熊猫>= 1.0

下面这张图表总结了熊猫身上一些最重要的基因转换。

到字符串的转换是简单的.astype(str),图中没有显示。

“硬”与“软”转换

注意,这里的“转换”既可以指将文本数据转换为实际数据类型(硬转换),也可以指为对象列中的数据推断更合适的数据类型(软转换)。为了说明区别,我们来看一下

df = pd.DataFrame({'a': ['1', '2', '3'], 'b': [4, 5, 6]}, dtype=object)
df.dtypes

a    object
b    object
dtype: object

# Actually converts string to numeric - hard conversion
df.apply(pd.to_numeric).dtypes

a    int64
b    int64
dtype: object

# Infers better data types for object data - soft conversion
df.infer_objects().dtypes

a    object  # no change
b     int64
dtype: object

# Same as infer_objects, but converts to equivalent ExtensionType
    df.convert_dtypes().dtypes
df = df.astype({"columnname": str})

# e。G -用于将列类型更改为字符串 #df是你的数据框架

如果你有各种各样的对象列,比如74个对象列和2个Int列,其中每个值都有字母表示单位:

import pandas as pd 
import numpy as np

dataurl = 'https://raw.githubusercontent.com/RubenGavidia/Pandas_Portfolio.py/main/Wes_Mckinney.py/nutrition.csv'
nutrition = pd.read_csv(dataurl,index_col=[0])
nutrition.head(3)

输出:

    name    serving_size    calories    total_fat    saturated_fat    cholesterol    sodium    choline    folate    folic_acid    ...    fat    saturated_fatty_acids    monounsaturated_fatty_acids    polyunsaturated_fatty_acids    fatty_acids_total_trans    alcohol    ash    caffeine    theobromine    water
0    Cornstarch    100 g    381    0.1g    NaN    0    9.00 mg    0.4 mg    0.00 mcg    0.00 mcg    ...    0.05 g    0.009 g    0.016 g    0.025 g    0.00 mg    0.0 g    0.09 g    0.00 mg    0.00 mg    8.32 g
1    Nuts, pecans    100 g    691    72g    6.2g    0    0.00 mg    40.5 mg    22.00 mcg    0.00 mcg    ...    71.97 g    6.180 g    40.801 g    21.614 g    0.00 mg    0.0 g    1.49 g    0.00 mg    0.00 mg    3.52 g
2    Eggplant, raw    100 g    25    0.2g    NaN    0    2.00 mg    6.9 mg    22.00 mcg    0.00 mcg    ...    0.18 g    0.034 g    0.016 g    0.076 g    0.00 mg    0.0 g    0.66 g    0.00 mg    0.00 mg    92.30 g
3 rows × 76 columns

nutrition.dtypes
name             object
serving_size     object
calories          int64
total_fat        object
saturated_fat    object
                  ...
alcohol          object
ash              object
caffeine         object
theobromine      object
water            object
Length: 76, dtype: object

nutrition.dtypes.value_counts()
object    74
int64      2
dtype: int64

将所有列转换为数值的一个好方法是使用正则表达式来替换单位,并使用astype(float)来更改列数据类型为float:

nutrition.index = pd.RangeIndex(start = 0, stop = 8789, step= 1)
nutrition.set_index('name',inplace = True)
nutrition.replace('[a-zA-Z]','', regex= True, inplace=True)
nutrition=nutrition.astype(float)
nutrition.head(3)

输出:

serving_size    calories    total_fat    saturated_fat    cholesterol    sodium    choline    folate    folic_acid    niacin    ...    fat    saturated_fatty_acids    monounsaturated_fatty_acids    polyunsaturated_fatty_acids    fatty_acids_total_trans    alcohol    ash    caffeine    theobromine    water
name
Cornstarch    100.0    381.0    0.1    NaN    0.0    9.0    0.4    0.0    0.0    0.000    ...    0.05    0.009    0.016    0.025    0.0    0.0    0.09    0.0    0.0    8.32
Nuts, pecans    100.0    691.0    72.0    6.2    0.0    0.0    40.5    22.0    0.0    1.167    ...    71.97    6.180    40.801    21.614    0.0    0.0    1.49    0.0    0.0    3.52
Eggplant, raw    100.0    25.0    0.2    NaN    0.0    2.0    6.9    22.0    0.0    0.649    ...    0.18    0.034    0.016    0.076    0.0    0.0    0.66    0.0    0.0    92.30
3 rows × 75 columns

nutrition.dtypes
serving_size     float64
calories         float64
total_fat        float64
saturated_fat    float64
cholesterol      float64
                  ...
alcohol          float64
ash              float64
caffeine         float64
theobromine      float64
water            float64
Length: 75, dtype: object

nutrition.dtypes.value_counts()
float64    75
dtype: int64

现在数据集是干净的,你只能用regex和astype()对这个数据帧进行数值操作。

如果你想收集单位,并粘贴在标题如胆固醇,你可以使用下面的代码:

nutrition.index = pd.RangeIndex(start = 0, stop = 8789, step= 1)
nutrition.set_index('name',inplace = True)
nutrition.astype(str).replace('[^a-zA-Z]','', regex= True)
units = nutrition.astype(str).replace('[^a-zA-Z]','', regex= True)
units = units.mode()
units = units.replace('', np.nan).dropna(axis=1)
mapper = { k: k + "_" + units[k].at[0] for k in units}
nutrition.rename(columns=mapper, inplace=True)
nutrition.replace('[a-zA-Z]','', regex= True, inplace=True)
nutrition=nutrition.astype(float)

用这个:

a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']]
df = pd.DataFrame(a, columns=['one', 'two', 'three'])
df

Out[16]:
  one  two three
0   a  1.2   4.2
1   b   70  0.03
2   x    5     0

df.dtypes

Out[17]:
one      object
two      object
three    object

df[['two', 'three']] = df[['two', 'three']].astype(float)

df.dtypes

Out[19]:
one       object
two      float64
three    float64