Pandas 如果可能,将字符串转换为数字;否则保留字符串值

Pandas convert strings to numeric if possible; else keep string values

我有一个 Pandas 数据框,其中的列看起来像这样:

df:

Column0   Column1     Column2
'MSC'       '1'        'R2'
'MIS'       'Tuesday'  '22'
'13'        'Finance'  'Monday'

总的来说,这些列中有实际的字符串,还有字符串格式的数值(整数)。

我发现 this 很好 post 关于 pd.to_numericastype() 方法,但我看不出是否或如何在我的案例中使用它们。

使用:

pd.to_numeric(df, errors = 'ignore')

只是导致跳过整列。我不想跳过整列,只想跳过那些无法转换的列中的字符串,继续下一个条目并尝试转换下一个字符串。

所以最后,我的数据框将如下所示:

df:

Column0   Column1     Column2
'MSC'       1          'R2'
'MIS'      'Tuesday'    22
 13        'Finance'  'Monday'

是否有一种有效的方法可以遍历这些列并实现这一点?

此致, 一月

编辑: 感谢您的所有建议!由于我仍然是 python 初学者,@coldspeed 和 @sacul 的答案对我来说更容易理解,所以我会选择其中之一!

100% 同意评论——在列中混合 dtype 是一个糟糕的主意,性能方面。

不过,作为参考,我会使用 pd.to_numericfillna:

df2 = df.apply(pd.to_numeric, errors='coerce').fillna(df)
print(df2)
  Column0  Column1 Column2
0     MSC        1      R2
1     MIS  Tuesday      22
2      13  Finance  Monday

列转换为 object dtype 以防止强制转换。当你提取 values:

时你可以看到这个
print(df2.values.tolist())
[['MSC', 1.0, 'R2'], ['MIS', 'Tuesday', 22.0], [13.0, 'Finance', 'Monday']]

我会根据结果应用 pd.to_numericerrors='coerce',并 update 原始数据框(请参阅评论中的注意事项):

# show original string type:
df.loc[0,'Column1']
# '1'

df.update(df.apply(pd.to_numeric, errors='coerce'))

>>> df
  Column0  Column1 Column2
0     MSC        1      R2
1     MIS  Tuesday      22
2      13  Finance  Monday

# show updated float type:
df.loc[0,'Column1']
# 1.0

或者您可以简单地使用 strisnumeric() 方法。我喜欢它,因为语法清晰,尽管根据 coldspeed 的评论,这在大 df 上会变得非常慢。

df = df.applymap(lambda x: int(x) if x.isnumeric() else x)

示例:

In [1]: import pandas as pd

In [2]: df = pd.DataFrame([['a','b','c'],['1','1a','c']],columns=['Col1','Col2','Col3'])

In [3]: df
Out[3]:
  Col1 Col2 Col3
0    a    b    c
1    1   1a    c

In [4]: df.Col1.map(lambda x: int(x) if x.isnumeric() else x)
Out[4]:
0    a
1    1
Name: Col1, dtype: object

使用 to_numeric + ignore

df=df.applymap(lambda x : pd.to_numeric(x,errors='ignore'))
df
  Column0  Column1 Column2
0     MSC        1      R2
1     MIS  Tuesday      22
2      13  Finance  Monday
df.applymap(type)
                 Column0                Column1                Column2
0          <class 'str'>  <class 'numpy.int64'>          <class 'str'>
1          <class 'str'>          <class 'str'>  <class 'numpy.int64'>
2  <class 'numpy.int64'>          <class 'str'>          <class 'str'>