【问题标题】:Unique values across columns row-wise in pandas with missing values具有缺失值的熊猫中跨列的唯一值
【发布时间】:2021-01-20 15:39:14
【问题描述】:

我有一个类似的数据框

import pandas as pd
import numpy as np

df = pd.DataFrame({"Col1": ['A', np.nan, 'B', 'B', 'C'],
                  "Col2": ['A', 'B', 'B', 'A', 'C'],
                  "Col3": ['A', 'B', 'C', 'A', 'C']})

我想为每一行获取跨列的唯一组合,并使用这些值创建一个新列,不包括缺失值。

我现在要做的代码是

def handle_missing(s):
    
    return np.unique(s[s.notnull()])
    
def unique_across_rows(data):
    
    
    unique_vals = data.apply(handle_missing, axis = 1)
    
    # numpy unique sorts the values automatically
    merged_vals = unique_vals.apply(lambda x: x[0] if len(x) == 1 else '_'.join(x))
    
    return merged_vals

df['Combos'] = unique_across_rows(df)

这将返回预期的输出:

       Col1    Col2  Col3   Combos
  0       A       A     A       A
  1     NaN       B     B       B
  2       B       B     C       B_C
  3       B       A     A       A_B
  4       C       C     C       C

在我看来,Pandas 中应该有一种更加矢量化的方法来做到这一点:我该怎么做?

【问题讨论】:

    标签: python-3.x pandas unique


    【解决方案1】:

    您可以尝试一个简单的列表推导式,这对于较大的数据帧可能更有效:

    df['combos'] = ['_'.join(sorted(k for k in set(v) if pd.notnull(k))) for v in df.values]
    

    或者您可以将上述列表推导式包装在一个更具可读性的函数中:

    def combos():
        for v in df.values:
            unique = set(filter(pd.notnull, v))
            yield '_'.join(sorted(unique))
    
    df['combos'] = list(combos())
    

      Col1 Col2 Col3 combos
    0    A    A    A      A
    1  NaN    B    B      B
    2    B    B    C    B_C
    3    B    A    A    A_B
    4    C    C    C      C
    

    【讨论】:

    • 列表推导式在一些较大的数据帧上被证明是最快的方法,并且生成器函数也不会慢很多。
    【解决方案2】:

    您也可以在axis=1 上使用agg/apply,如下所示:

    df['Combos'] = df.agg(lambda x: '_'.join(sorted(x.dropna().unique())),axis=1)
    

    print(df)
    
      Col1 Col2 Col3 Combos
    0    A    A    A      A
    1  NaN    B    B      B
    2    B    B    C    B_C
    3    B    A    A    A_B
    4    C    C    C      C
    

    【讨论】:

      【解决方案3】:

      尝试(后面的解释)

      df['Combos'] = (df.stack()              # this removes NaN values
                        .sort_values()        # so we have A_B instead of B_A in 3rd row
                        .groupby(level=0)     # group by original index
                        .agg(lambda x: '_'.join(x.unique()))  # join the unique values
                     )
      

      输出:

        Col1 Col2 Col3 Combos
      0    A    A    A      A
      1  NaN    B    B      B
      2    B    B    C    B_C
      3    B    A    A    A_B
      4    C    C    C      C
      

      【讨论】:

        【解决方案4】:

        用字符串占位符“-”填充 nan。从 col1,col2,col3 列表中创建一个唯一数组并删除占位符。用 '-' 连接唯一的数组值

        import pandas as pd
        import numpy as np
        
        def unique(list1): 
           if '-' in list1:
               list1.remove('-')
           x = np.array(list1) 
           return (np.unique(x))
        
        df = pd.DataFrame({"Col1": ['A', np.nan, 'B', 'B', 'C'],
                      "Col2": ['A', 'B', 'B', 'A', 'C'],
                      "Col3": ['A', 'B', 'C', 'A', 'C']}).fillna('-')
        
         s="-"
         for key,row in df.iterrows():
             df.loc[key,'combos']=s.join(unique([row.Col1, row.Col2, row.Col3])) 
        
         print(df.head())
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-01-22
          • 2015-01-14
          • 2020-10-20
          • 2017-02-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多