在熊猫数据框中按行应用时如何保留数据类型?

Posted

技术标签:

【中文标题】在熊猫数据框中按行应用时如何保留数据类型?【英文标题】:How do I preserve datatype when using apply row-wise in pandas dataframe? 【发布时间】:2017-11-06 18:43:46 【问题描述】:

我遇到了一个奇怪的问题,即在数据帧上按行使用 apply 函数不会保留数据帧中值的数据类型。有没有办法在保留原始数据类型的数据帧上逐行应用函数?

下面的代码演示了这个问题。如果在下面的 format 函数中没有 int(...) 转换,则会出现错误,因为数据帧中的 int 在传递到 func 时被转换为浮点数。

import pandas as pd

df = pd.DataFrame('int_col': [1, 2], 'float_col': [1.23, 4.56])
print(df)
print(df.dtypes)

def func(int_and_float):
    int_val, float_val = int_and_float
    print('int_val type:', type(int_val))
    print('float_val type:', type(float_val))
    return 'int-:03d_float-:5.3f'.format(int(int_val), float_val)

df['string_col'] = df[['int_col', 'float_col']].apply(func, axis=1)
print(df)

这是运行上述代码的输出:

   float_col  int_col
0       1.23        1
1       4.56        2
float_col    float64
int_col        int64
dtype: object
int_val type: <class 'numpy.float64'>
float_val type: <class 'numpy.float64'>
int_val type: <class 'numpy.float64'>
float_val type: <class 'numpy.float64'>
   float_col  int_col           string_col
0       1.23        1  int-001_float-1.230
1       4.56        2  int-002_float-4.560

请注意,即使 dfint_col 列具有 dtype int64,当该列中的值传递到函数 func 时,它们突然具有 dtype numpy.float64,我必须使用 @987654332 @ 在函数的最后一行进行转换,否则该行会出错。

如有必要,我可以按这里的方式处理此问题,但我真的很想了解为什么会出现这种意外行为。

【问题讨论】:

【参考方案1】:

你的整数被upcasted变成浮点数。如果可能,Pandas(和 NumPy)将尝试将 Series(或 ndarray)制作成单一数据类型。据我所知,没有记录向上转换的确切规则,但是您可以看到使用numpy.find_common_type 将如何向上转换不同的类型。

您可以通过在调用 apply 之前将 DataFrame 转换为“Object”类型来欺骗 Pandas 和 NumPy 保持原始数据类型,如下所示:

df['string_col'] = df[['int_col', 'float_col']].astype('O').apply(func, axis=1)

让我们分解这里发生的事情。首先,我们做.astype('O')之后df会发生什么?

as_object = df[['int_col', 'float_col']].astype('O')
print(as_object.dtypes)

给予:

int_col      object
float_col    object
dtype: object

好的,现在两列都具有相同的 dtype,即 object。从之前我们就知道apply()(或其他任何从 DataFrame 中提取一行的东西)会尝试将两列转换为相同的 dtype,但它会看到它们已经相同,所以没有什么可做的。

但是,我们仍然能够获取原始整数和浮点数,因为dtype('O') 表现为某种容器类型,可以容纳任何 python 对象。通常,当 Series 包含不应混合的类型(如字符串和整数)或 NumPy 不理解的任何 python 对象时使用它。

【讨论】:

将数据转换为字符串以保持 int 或 float 的外观的好主意。 +1 连续制作一个系列似乎是一个奇怪的选择,但我想这适用于很多应用程序。 .astype('O') 这件事就像一个魅力!为什么将 DataFrame 转换为“Object”类型会使其将原始数据类型发送到func?我本来希望看到我的打印语句会说int_val type: &lt;class 'str'&gt;,但实际上是int_val type: &lt;class 'int'&gt; 用解释更新了我的答案。这有帮助吗?【参考方案2】:

发生的情况是,当您执行 apply(axis=1) 时,您的输入行将作为 pandas 系列传递。而且,在 pandas 中,一个系列有一个 dtype。由于您的行同时具有整数和浮点数,因此整个系列都被强制转换为浮点数。

import pandas as pd

df = pd.DataFrame('int_col': [1, 2], 'float_col': [1.23, 4.56])

def func(int_and_float):
    int_val, float_val = int_and_float
    print('\n')
    print('Prints input series')
    print(int_and_float)
    print('\n')
    return 'int-:03d_float-:5.3f'.format(int(int_val), float_val)

df['string_col'] = df[['int_col', 'float_col']].apply(func, axis=1)

输出:

Prints input series
int_col      1.00
float_col    1.23
Name: 0, dtype: float64




Prints input series
int_col      2.00
float_col    4.56
Name: 1, dtype: float64

【讨论】:

不是超级重要,但是从 int64 到 float64 是“向下转换”还是“向上转换”,或者只是转换,因为它们具有相同的大小? @BenLindsay 我不确定。我把它改成了铸造的。我必须查看 pandas 源代码或询问这里的 pandas 神之一来确定。但是,我确信这就是您的整数被转换为浮点数的原因。

以上是关于在熊猫数据框中按行应用时如何保留数据类型?的主要内容,如果未能解决你的问题,请参考以下文章

如何在熊猫中迭代数据框时保留数据类型?

如何在熊猫数据框中执行按行if和数学运算

在 Spark 数据框中的 n 列中按行查找最频繁的值

如何在熊猫数据框中按条件累计计算几列[重复]

在熊猫数据框中按 MinMaxScaler 分组

如何合并熊猫数据框中的两列,堆叠在顶部