【问题标题】:Pandas convert strings to numeric if possible; else keep string values如果可能,Pandas 将字符串转换为数字;否则保留字符串值
【发布时间】:2018-12-04 23:04:27
【问题描述】:

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

df:

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

总的来说,这些列中包含实际的字符串,但也包含字符串格式的数值(整数)。

我发现 this 关于 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 的答案对我来说更容易理解,所以我会选择其中一个!

【问题讨论】:

  • 这不适合 pandas 模型。您正在单个列中寻找混合类型...除非您只是更喜欢 pandas 语法,否则您将失去在数据处理中可能获得的任何效率收益
  • 您还需要保留不会转换的字符串吗?如果是这样,将它们移动到新列是否可以接受?单列中的混合数据类型不起作用。
  • @roganjosh,虽然有时当您使用 pandas 清理收到的混合类型数据时,这是相关的。

标签: python string pandas dataframe numeric


【解决方案1】:

100% 同意 cmets — 在列中混合 dtypes 是一个糟糕的想法,从性能角度来看。

不过,作为参考,我会使用 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']]

【讨论】:

    【解决方案2】:

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

    # 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
    

    【讨论】:

      【解决方案3】:

      使用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'>
      

      【讨论】:

        【解决方案4】:

        或者您可以简单地使用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
        

        【讨论】:

        • 请添加免责声明,对于大型 DataFrame,这可能会变得非常慢。
        猜你喜欢
        • 2020-02-19
        • 2022-11-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-25
        • 2020-11-05
        相关资源
        最近更新 更多