为什么pandas Series.str将数字转换为NaN?

7
这可能是我基础理解上的误解,但我期望 pandas.Series.strpandas.Series 的值转换为字符串。

然而,当我执行以下操作时,系列中的数字值被转换为 np.nan:
df = pd.DataFrame({'a': ['foo    ', 'bar', 42]})
df = df.apply(lambda x: x.str.strip() if x.dtype == 'object' else x)
print(df)

Out:
     a
0  foo
1  bar
2  NaN

如果我先对每列应用str函数,那么数值将被转换为字符串而不是np.nan

df = pd.DataFrame({'a': ['foo    ', 'bar', 42]})
df = df.apply(lambda x: x.apply(str) if x.dtype == 'object' else x)
df = df.apply(lambda x: x.str.strip() if x.dtype == 'object' else x)
print(df)

Out:
     a
0  foo
1  bar
2   42

文档在这个话题上相对缺乏。我漏掉了什么?
2个回答

5
在这一行中:
df.apply(lambda x: x.str.strip() if x.dtype == 'object' else x)
x.dtype查看整个系列(列),这一列不是数字。因此,整个列的操作就像字符串一样。
在第二个示例中,数字没有被保留,它是一个字符串'42'
输出结果的差异是由于pandas的str和python的str之间的差异。
在pandas的情况下,.str不是一种转换,而是一种访问器,它允许您对每个元素执行.strip()操作。这意味着您尝试将.strip()应用于整数。这会引发异常,pandas通过返回Nan来响应异常。
.apply(str)的情况下,您实际上正在将值转换为字符串。稍后,当您应用.strip()时,由于该值已经是字符串,因此可以进行剥离。

2
你正在使用.apply的方式是按进行的,因此请注意:
>>> df.apply(lambda x: x.str.strip() if x.dtype == 'object' else x)
     a
0  foo
1  bar
2  NaN

它作用于列,x.dtype 总是 object 类型。

>>> df.apply(lambda x:x.dtype)
a    object
dtype: object

如果您按行进行操作,使用axis=1,您仍将看到相同的行为:
>>> df.apply(lambda x:x.dtype, axis=1)
0    object
1    object
2    object
dtype: object

看这里:

>>> df.apply(lambda x: x.str.strip() if x.dtype == 'object' else x, axis=1)
     a
0  foo
1  bar
2  NaN
>>>

因此,当它说“object” dtype时,它意味着Python对象。因此,请考虑一个非对象数值列:
>>> S = pd.Series([1,2,3])
>>> S.dtype
dtype('int64')
>>> S[0]
1
>>> S[0].dtype
dtype('int64')
>>> isinstance(S[0], int)
False

相比于这个object类型的列:

>>> df
         a
0  foo
1      bar
2       42
>>> df['a'][2]
42
>>> isinstance(df['a'][2], int)
True
>>>

您实际上正在执行以下操作:
>>> s = df.a.astype(str).str.strip()
>>> s
0    foo
1    bar
2     42
Name: a, dtype: object
>>> s[2]
'42'

注意:
>>> df.apply(lambda x: x.apply(str) if x.dtype == 'object' else x).a[2]
'42'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接