【问题标题】: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 @ 在函数的最后一行进行转换,否则该行会出错。

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

【问题讨论】:

    标签: python pandas


    【解决方案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 神之一来确定。但是,我确信这就是您的整数被转换为浮点数的原因。
    猜你喜欢
    • 2018-07-21
    • 1970-01-01
    • 1970-01-01
    • 2017-08-02
    • 2019-04-01
    • 1970-01-01
    • 2021-08-08
    • 2021-03-12
    • 1970-01-01
    相关资源
    最近更新 更多