在pandas中获取一行中唯一值的数量

4
假设我有以下数据框:
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())) ??
4个回答

9
只需要使用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)

6
使用列表生成式...与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)

出于好奇,你认为这三种方法中哪一种会有最佳性能?看到那将是很有趣的。--领先一步! - user10332687
这个似乎更快:df.nunique(1) - df.isnull().any(1).astype(int) - Vaishali
1
当然可以添加。 - Vaishali
1
@ayhan 我意识到我搞砸了。nunique确实忽略NaN! - cs95
@PraysonW.Daniel,谢谢,我的错,没有测试它,我已经评论并点赞了你的答案。 - cs95
显示剩余6条评论

2
更抽象的解决方案:
df['num_uniq']=df.nunique(axis=1)

0

虽然不如 coldspeed 的 set() 答案快,但你也可以这样做

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

首先使用df.T获取df数据框的转置,然后使用nunique()函数获取不包括NaN值的唯一值计数。

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

现在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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接