我想使用通用模式将函数应用于Pandas DataFrame中的每一列,但是该函数应以列数据类型为条件。
听起来很简单。但是我在测试数据类型时发现了一种怪异的行为,无法在文档中找到任何地方或搜索其原因。
考虑此repex:
import pandas as pd
toydf = pd.DataFrame(dict(
A = [1, 2, 3],
B = [1.1, 1.2, 1.3],
C = ['1', '2', '3'],
D = [True, True, False]
))
分别检查它们是dtype('int64'), dtype('float64'), dtype('O'), dtype('bool')
的dtypes
但是,如果我使用apply
函数,则传递给该函数的所有列都是dtype: object
。
def dtype_fn(the_col):
print(the_col)
return(the_col.dtype)
toydf.apply(dtype_fn)
toydf.apply(dtype_fn)
0 1
1 2
2 3
Name: A, dtype: object
0 1.1
1 1.2
2 1.3
Name: B, dtype: object
0 1
1 2
2 3
Name: C, dtype: object
0 True
1 True
2 False
Name: D, dtype: object
Out[167]:
A object
B object
C object
D object
dtype: object
这是为什么?我做错了什么?为什么列不保留原始数据类型?
这是一种可行的方法,可以产生我想要的输出:(但是出于封装的原因,我不喜欢它)
def dtype_fn2(col_name):
return(toydf[col_name].dtype)
[dtype_fn2(col) for col in toydf.columns]
Out[173]: [dtype('int64'), dtype('float64'), dtype('O'), dtype('bool')]
答案 0 :(得分:7)
此comment是正确的。此行为是设计使然。对于给定的所有dtype,Pandas“应用”在类型层次结构中最高的类型。
考虑仅将该功能应用于“ A”,
df[['A']].apply(dtype_fn)
int64
A int64
dtype: object
同样,只有“ A”和“ B”,
df[['A', 'B']].apply(dtype_fn)
float64
float64
A float64
B float64
dtype: object
由于您有多种类型,包括原始DataFrame中的字符串,因此它们的通用类型均为object
。
现在,这解释了该行为,但是我仍然需要解决此问题。熊猫提供了一种有用的方法:Series.infer_objects
,它可以推断dtype并执行“软转换”。
如果确实需要函数中的类型,则可以在调用dtype
之前执行软转换。这样会产生预期的结果:
def dtype_fn(the_col):
the_col = the_col.infer_objects()
print(the_col.dtype)
return(the_col.dtype)
df.apply(dtype_fn)
int64
float64
object
bool
A int64
B float64
C object
D bool
dtype: object
答案 1 :(得分:2)
您的dtype_fn
的实际输入是Pandas Series对象。您可以通过稍微修改方法来访问基础类型。
def dtype_fn(the_col):
print(the_col.values.dtype)
return(the_col.values.dtype)
有关这种情况的更多信息,请查看此answer。上面写着
这不是错误,但是是由于numpy dtype表示形式引起的: https://docs.scipy.org/doc/numpy/reference/arrays.scalars.html。
答案 2 :(得分:0)
您希望在数据帧上使用apply fn,但是您忘记了基本类型转换(大多数OOP语言都存在此问题)。快速修复如下:
def selectiveapply(row):
return(type(row[0]))
toydf=toydf.T
toydf["type"]=toydf.apply(selectiveapply,axis=1)
apply也可以通过设置axis = 0逐列应用。玩弄一下这些功能,最终您会得到答案。