在pandas中更改列类型

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

  1. to_numeric() - 提供功能以安全地将非数值类型(例如字符串)转换为合适的数值类型。(另见 to_datetime()to_timedelta()。)
  2. astype() - (几乎)任何类型转换为(几乎)任何其他类型(即使这样做不一定合理)。还允许你将类型转换为分类类型(非常有用)。
  3. infer_objects() - 一个实用方法,如果可能的话,将包含 Python 对象的列转换为 pandas 类型。
  4. convert_dtypes() - DataFrame 列转换为支持 pd.NA(pandas 的对象,用于表示缺失值)的“最佳可能”数据类型。

1. to_numeric()

将非数值对象(如字符串)转换为整数或浮点数的最好方法是使用 pandas 中的 to_numeric() 函数。这个函数会尝试将非数值对象(如字符串)转换为适当的整数或浮点数。

基本用法

to_numeric() 的输入可以是一个 Series 或者一个 DataFrame 的单列。

s = pd.Series(["8", "6", "7.5", "3", "0.9"])  # 合字符串和数值
s = pd.to_numeric(s)  # 转换为浮点值

可以看到,返回了一个新的 Series。你可以将其赋值给一个变量或列名以便继续使用:

my_series = pd.to_numeric(my_series)

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

df = df.apply(pd.to_numeric)  # 转换 `DataFrame` 的所有列

或者只转换特定的列:

df[["a", "b"]] = df[["a", "b"]].apply(pd.to_numeric)

只要你的值都可以被转换,这可能就是你需要的所有操作。

错误处理

但如果有些值无法转换为数值类型怎么办?

to_numeric() 接受一个 errors 关键字参数,允许你强制非数值值为 NaN,或者简单地忽略包含这些值的列。

以下是一个使用字符串 Series 的示例,该 Series 有对象数据类型:

s = pd.Series(['1', '2', '4.7', 'pandas', '10'])

默认行为是在无法转换值时引发异常。在这种情况下,它无法处理字符串 ‘pandas’:

pd.to_numeric(s, errors='raise')

ValueError: Unable to parse string

与其失败,我们可能希望 ‘pandas’ 被视为缺失或无效的数值,并将其转换为 NaN,如下所示:

pd.to_numeric(s, errors='coerce')

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

pd.to_numeric(s, errors='ignore')

原始 Series 将保持不变。

最后一个选项特别适用于转换整个 DataFrame,但不知道哪些列可以可靠地转换为数值类型。在这种情况下,只需写:

df.apply(pd.to_numeric, errors='ignore')

该函数将应用于 DataFrame 的每一列。可以转换为数值类型的列将被转换,而不能转换的列(例如,它们包含非数字字符串或日期)将保持不变。

下采样 (Downcasting)

默认情况下,使用 to_numeric() 换时,你会得到 int64float64 数据类型(或者平台原生的任何整数宽度)。

这通常是你要的结果,但如果你想要节省内存并使用更紧凑的数据类型,比如 float32int8 么办?

to_numeric() 给你选择下采样的选项,可以转换为 'integer''signed''unsigned''float'。以下是一个简单的整数类型 Series 示例:

s = pd.Series([1, 2, -7])

下采样到 'integer' 使用可以容纳值的最小可能整数:

pd.to_numeric(s, downcast='integer')

下采样到 'float' 同样选择比正常浮点类型更小的类型:

pd.to_numeric(s, downcast='float')

结果将是 float32

2. astype()

astype() 方法允许你明确指定 DataFrame 或 Series 的数据类型。它非常灵活,可以尝试从一种类型转换为另一种类型。

基本用法

只需选择一个类型:你可以使用 NumPy 数据类型(例如 np.int16)、一些 Python 类型(例如 bool),或者 pandas 特定的类型(如分类数据类型)。

在你想转换的对象上调用该方法,astype() 将尝试并为你进行转换:

# 将所有 DataFrame 列转换为 int64 类型
df = df.astype(int)

# 列 "a" 转换为 int64 类型,将列 "b" 转换为复数类型
df = df.astype({"a": int, "b": complex})

# 将 Series 转换为 float16 类型
s = s.astype(np.float16)

# 将 Series 转换为 Python 字符串
s = s.astype(str)

# 将 Series 转换为分类类型 - 请参阅文档以获取更多详细信息
s = s.astype('category')

请注意我说的是“尝试”——如果 astype() 不知道如何转换 Series 或 DataFrame 中的值,它将引发错误。例如,如果你有一个 NaNinf ,尝试将其转换为整数时会得到错误。

从 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()

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.NA 缺失值的最佳可能数据类型。

这里的“最佳可能”是指最适合存储这些值的数据类型。例如,如果所有值都是整数(或缺失值),则会转换为 pandas 整数类型;如果 Python 整数对象的列被转换为 Int64,NumPy int32 值的列将变为 pandas 数据类型 Int32

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

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

由于列 ‘a’ 包含整数值,因此被转换为 Int64 类型(能够存储缺失值,与 int64 不同)。

列 ‘b’ 包含字符串对象,因此被转换为 pandas string 类型。

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

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

现在列 ‘a’ 仍然是一个对象列:pandas 知道它可以被描述为一个整数列(内部运行了 infer_dtype),但没有推断出它应该具有的确切数据类型,因此没有转换它。列 ‘b’ 再次被转换为 string 类型,因为它被识别为持有字符串值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李星星BruceL

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值