【问题标题】:How to select only string (non-numeric) columns when there are mixed type columns?有混合类型列时如何仅选择字符串(非数字)列?
【发布时间】:2022-01-20 20:46:03
【问题描述】:

假设我有一个包含三列数据类型(objectintfloat)的数据框:

df = pd.DataFrame({
    'col1': [1, 2, np.nan, 5],
    'col2': [3, 4, 5, 4],
    'col3': ['This is a text column'] * 4
})

我需要将np.nan 替换为None,这是一个对象(因为None 在导入PostgresSQL 时变为NULL)。

df.replace({np.nan: None}, inplace=True)

我认为(如果我错了,请纠正我)None 不能在任何 NumPy/Pandas 数组中使用,除了 dtype 为 object 的数组。所以上面的'col1'在replace之后变成了object列。现在,如果我只想对字符串列进行子集化(在这种情况下应该只是'col3'),我不能再使用df.select_dtypes(include=object),它会返回所有object dtype 列,包括'col1'。我一直在使用这个 hacky 解决方案来解决这个问题:

# Select only object columns, which includes 'col1'
(df.select_dtypes(include=object)
   # Hack, after this, 'col1' becomes float again since None becomes np.nan
   .apply(lambda col: col.apply(lambda val: val))
   # Now select only the object columns
   .select_dtypes(include=object))

我想知道是否有惯用(或不那么老套)的方法来实现这一点。这个用例确实出现了,因为我需要从数据框中获取字符串列,其中有数字(floatint)列,其中缺少由None 表示的值而不是np.nan

另一种解决方案

基于以下 Mayank Porwal 的解决方案:

# The list comprehension returns a boolean list
df.loc[:, [pd.to_numeric(df[col], errors='coerce').isna().all() for col in df.columns.tolist()]]

【问题讨论】:

    标签: python pandas numpy


    【解决方案1】:

    根据您的示例 df,您可以执行以下操作:

    np.nan 替换为None 后,col1 变为object

    In [1413]: df.dtypes
    Out[1413]: 
    col1    object
    col2     int64
    col3    object
    dtype: object
    

    要选择仅包含字符串的列,您可以使用pd.to_numericerrors='coerce',并使用isna 检查该列是否包含所有Nan

    In [1416]: cols = df.select_dtypes('object').columns.tolist()
    In [1422]: cols
    Out[1422]: ['col1', 'col3']
    
    In [1424]: for i in cols:
          ...:     if pd.to_numeric(df[i], errors='coerce').isna().all():
          ...:         print(f'{i}: String col')
          ...:     else:
          ...:         print(f'{i}: number col')
          ...: 
    col1: number col
    col3: String col
    

    【讨论】:

    • 我喜欢这个。在pd.to_numeric() 中很好地使用了coerce 参数。绝对更健壮和惯用。它非常适合我的用例的功能框架。
    【解决方案2】:

    反转你的 2 个操作:

    1. 提取object 列并处理它们。
    2. 在导出到 pgsql 之前将 NaN 转换为 None
    >>> df.dtypes
    col1    float64
    col2      int64
    col3     object
    dtype: object
    
    # Step 1: process string columns
    >>> df.update(df.select_dtypes('object').agg(lambda x: x.str.upper()))
    
    # Step 2: replace nan by None
    >>> df.replace({np.nan: None}, inplace=True)
    
    >>> df
       col1  col2                   col3
    0   1.0     3  THIS IS A TEXT COLUMN
    1   2.0     4  THIS IS A TEXT COLUMN
    2  None     5  THIS IS A TEXT COLUMN
    3   5.0     4  THIS IS A TEXT COLUMN
    

    【讨论】:

      猜你喜欢
      • 2013-05-06
      • 1970-01-01
      • 1970-01-01
      • 2016-05-22
      • 1970-01-01
      • 2023-03-16
      • 1970-01-01
      • 2014-04-02
      • 1970-01-01
      相关资源
      最近更新 更多