【问题标题】:Get count unique values in a row in pandas在熊猫中连续获取计数唯一值
【发布时间】:2019-05-20 14:41:05
【问题描述】:

假设我有以下数据框:

0     1        2
new   NaN      NaN
new   one      one
a     b        c
NaN   NaN      NaN

如何获取一行中唯一(非 NaN)值的数量,例如:

0     1        2       _num_unique_values
new   NaN      NaN     1
new   one      one     2
a     b        c       3
NaN   NaN      NaN     0

我想应该是这样的:

df['_num_unique_values'] = len(set(df.loc.tolist())) ??

【问题讨论】:

    标签: python python-3.x pandas


    【解决方案1】:

    只需使用 nunique(axis=1)。

    import numpy as np
    import pandas as pd
    
    data={0:['new','new','a',np.nan],
         1:[np.nan,'one','b', np.nan],
         2:[np.nan,np.nan,'c',np.nan]}
    df = pd.DataFrame(data)
    
    # print(df.nunique(axis=1))
    
    df['num_unique'] = df.nunique(axis=1)
    

    【讨论】:

      【解决方案2】:

      更抽象的解决方案:

      df['num_uniq']=df.nunique(axis=1)
      

      【讨论】:

        【解决方案3】:

        使用列表推导式......与set:

        df['num_uniq'] = [len(set(v[pd.notna(v)].tolist())) for v in df.values]
        df
        
             0    1    2  num_uniq
        0  new  NaN  NaN         1
        1  new  one  one         2
        2    a    b    c         3
        3  NaN  NaN  NaN         0
        

        您可以使用 stackgroupbynunique 来做到这一点。

        # df.join(df.stack().groupby(level=0).nunique().to_frame('num_uniq'))
        df['num_uniq'] = df.stack().groupby(level=0).nunique()
        df
        
             0    1    2  num_uniq
        0  new  NaN  NaN       1.0
        1  new  one  one       2.0
        2    a    b    c       3.0
        3  NaN  NaN  NaN       NaN
        

        还有一个选项是applynunique

        df['num_uniq'] = df.apply(pd.Series.nunique, axis=1)
        df
        
             0    1    2  num_uniq
        0  new  NaN  NaN         1
        1  new  one  one         2
        2    a    b    c         3
        3  NaN  NaN  NaN         0
        

        性能

        df_ = df
        df = pd.concat([df_] * 1000, ignore_index=True)
        
        %timeit df['num_uniq'] = [len(set(v[pd.notna(v)])) for v in df.values]
        %timeit df['num_uniq'] = df.stack().groupby(level=0).nunique()
        %timeit df['num_uniq'] = df.apply(pd.Series.nunique, axis=1)
        %timeit df['num_uniq'] = df.nunique(1)
        
        196 ms ± 10.1 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
        6.34 ms ± 343 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
        679 ms ± 24 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
        3.21 ms ± 343 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
        

        【讨论】:

        • 出于好奇,您认为接近的三个中哪一个的性能最好?那会很有趣。 -- 领先一步!
        • @DavidL 希望编辑解决您的问题......我很惊讶列表理解比我想象的要慢:-)
        • 这个似乎更快:df.nunique(1) - df.isnull().any(1).astype(int)
        • 是的,你可以添加
        • @ayhan 我意识到我搞砸了。 nunique 确实忽略了 NaN!
        【解决方案4】:

        它没有coldspeed 对set() 的回答那么快,但你也可以这样做

        df['_num_unique_values'] = df.T.nunique()
        

        首先使用df.Tdf 数据帧进行转置,然后使用nunique() 获取除NaNs 之外的唯一值的计数。

        这将作为新列添加到原始数据框中。

        df 现在是

            0   1   2   _num_unique_values
        0   new nan nan 1
        1   new one one 2
        2   a   b   c   3
        3   nan nan nan 0
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-05-30
          • 2021-03-17
          相关资源
          最近更新 更多