【问题标题】:Replace low frequency categorical values from pandas.dataframe while ignoring NaNs替换 pandas.dataframe 中的低频分类值,同时忽略 NaN
【发布时间】:2017-01-11 04:42:55
【问题描述】:

如何替换 pandas.DataFrame 中某些列中很少出现的值,即低频(同时忽略 NaN)?

例如,在以下数据框中,假设我想替换列 A 或 B 中在各自列中出现次数少于 3 次的任何值。我想用“其他”替换这些:

import pandas as pd
import numpy as np

df = pd.DataFrame({'A':['ant','ant','cherry', pd.np.nan, 'ant'], 'B':['cat','peach', 'cat', 'cat', 'peach'], 'C':['dog','dog',pd.np.nan, 'emu', 'emu']})
df
   A   |   B   |  C  |
----------------------
ant    | cat   | dog |
ant    | peach | dog |
cherry | cat   | NaN |
NaN    | cat   | emu |
ant    | peach | emu |

换句话说,在 A 列和 B 列中,我想替换那些出现两次或更少的值(但不理会 NaN)。

所以我想要的输出是:

   A   |   B   |  C  |
----------------------
ant    | cat   | dog |
ant    | other | dog |
other  | cat   | NaN |
NaN    | cat   | emu |
ant    | other | emu |

这与之前发布的问题有关:Remove low frequency values from pandas.dataframe

但那里的解决方案导致“AttributeError:'NoneType'对象没有属性'any。'”(我想是因为我有NaN值?)

【问题讨论】:

    标签: python-3.x pandas


    【解决方案1】:

    这与Change values in pandas dataframe according to value_counts() 非常相似。您可以向 lambda 函数添​​加条件以排除列“C”,如下所示:

    df.apply(lambda x: x.mask(x.map(x.value_counts())<3, 'other') if x.name!='C' else x)
    Out: 
           A      B    C
    0    ant    cat  dog
    1    ant  other  dog
    2  other    cat  NaN
    3    NaN    cat  emu
    4    ant  other  emu
    

    这基本上是对列进行迭代。对于每一列,它会生成值计数并使用该系列进行映射。这允许x.mask 检查计数是否小于 3 的条件。如果是这种情况,它会返回“其他”,如果不是,则使用实际值。最后,条件检查列名。

    通过将 lambda 的条件从 x.name!='C' 更改为 x.name not in 'CDEF'x.name not in ['C', 'D', 'E', 'F'],可以将其推广到多列。

    【讨论】:

      【解决方案2】:

      使用辅助函数和replace

      def replace_low_freq(df, threshold=2, replacement='other'):
          s = df.stack()
          c = s.value_counts()
          m = pd.Series(replacement, c.index[c <= threshold])
          return s.replace(m).unstack()
      
      cols = list('AB')
      replace_low_freq(df[cols]).join(df.drop(cols, 1))
      
             A      B    C
      0    ant    cat  dog
      1    ant  other  dog
      2  other    cat  NaN
      3   None    cat  emu
      4    ant  other  emu
      

      【讨论】:

      • 不错的清洁解决方案 +1
      【解决方案3】:

      你可以使用:

      #added one last row for complicated df
      df = pd.DataFrame({'A':['ant','ant','cherry', pd.np.nan, 'ant', 'd'], 
                         'B':['cat','peach', 'cat', 'cat', 'peach', 'm'], 
                         'C':['dog','dog',pd.np.nan, 'emu', 'emu', 'k']})
      print (df)
              A      B    C
      0     ant    cat  dog
      1     ant  peach  dog
      2  cherry    cat  NaN
      3     NaN    cat  emu
      4     ant  peach  emu
      5       d      m    k
      

      使用value_countsboolean indexing 查找所有替换值:

      a = df.A.value_counts()
      a = a[a < 3].index
      print (a)
      Index(['cherry', 'd'], dtype='object')
      
      b = df.B.value_counts()
      b = b[b < 3].index
      print (b)
      Index(['peach', 'm'], dtype='object')
      

      然后replacedict comprehension 如果要替换的值更多:

      df.A = df.A.replace({x:'other' for x in a})
      df.B = df.B.replace({x:'other' for x in b})
      print (df)
             A      B    C
      0    ant    cat  dog
      1    ant  other  dog
      2  other    cat  NaN
      3    NaN    cat  emu
      4    ant  other  emu
      5  other  other    k
      

      一起循环:

      cols = ['A','B']
      for col in cols:
          val = df[col].value_counts()
          y = val[val < 3].index
          df[col] = df[col].replace({x:'other' for x in y})
      print (df)
             A      B    C
      0    ant    cat  dog
      1    ant  other  dog
      2  other    cat  NaN
      3    NaN    cat  emu
      4    ant  other  emu
      5  other  other    k
      

      【讨论】:

      • 嗯,所以这适用于这个示例 df,但是当我尝试使用我的实际数据执行此操作时,我得到一个带有替换 w/dict 理解行的错误:ValueError: not enough values to unpack (预期 2,得到 0)。知道那里会发生什么吗?
      • 我不确定,也许有必要转换为列表 - df[col] = df[col].replace({x:'other' for x in y.tolist()})
      猜你喜欢
      • 2019-07-24
      • 1970-01-01
      • 2022-07-08
      • 2023-04-09
      • 2021-10-28
      • 2016-06-15
      • 2021-09-17
      • 2019-09-24
      • 1970-01-01
      相关资源
      最近更新 更多