在熊猫数据框中按行应用时如何保留数据类型?
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
请注意,即使 df
的 int_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: <class 'str'>
,但实际上是int_val type: <class 'int'>
用解释更新了我的答案。这有帮助吗?【参考方案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 神之一来确定。但是,我确信这就是您的整数被转换为浮点数的原因。以上是关于在熊猫数据框中按行应用时如何保留数据类型?的主要内容,如果未能解决你的问题,请参考以下文章