【问题标题】:Pandas: Get all columns that have constant valuePandas:获取所有具有恒定值的列
【发布时间】:2018-05-29 10:32:59
【问题描述】:

我想获取在每列的所有行中具有相同值的列的名称。

我的数据:

   A   B  C  D
0  1  hi  2  a
1  3  hi  2  b
2  4  hi  2  c

期望的输出:

['B', 'C']

代码:

import pandas as pd

d = {'A': [1,3,4], 'B': ['hi','hi','hi'], 'C': [2,2,2], 'D': ['a','b','c']}
df = pd.DataFrame(data=d)

我一直在玩 df.columns.any(),但不知道该怎么做。

【问题讨论】:

标签: python pandas


【解决方案1】:

使用 pandas 不太知名的内置函数 nunique()

df.columns[df.nunique() <= 1]
Index(['B', 'C'], dtype='object')

注意事项:

  • 如果您希望将 na 计为单独的值,请使用 nunique(dropna=False) 选项
  • 这是最干净的代码,但不是最快的。 (但一般而言,代码应优先考虑清晰性和可读性)。

【讨论】:

  • @Mohamed Thasin 啊解决方案是我的数据集(30.000 行 195 列)中最快的解决方案,但是由于我重视可读性而不是速度,所以我选择您的 nunique() 解决方案 - 谢谢!跨度>
  • 此答案仅适用于提供的示例数据,但不回答问题。如果其中一列有两行具有相同的值,它将报告此答案,并且问题是关于具有恒定值的列。 pd.Series(data=[1, 2, 2, 3]).is_unique => False 这当然是这种方法的预期行为
  • @Mousa:我展示的第二个解决方案,使用df.nunique()==1 确实有效。更新了这个。感谢您的评论
  • nuniquedropna=True(默认)报告 cols 只有 NaNs 为零,因此 df.nunique()&lt;=1 似乎是更通用的解决方案。
  • @NichtJens:太好了,感谢您的改进! nunique() 完全没有文档记录,涉及它的食谱也是如此......必须在 pandas 文档中提交一些 docbugs/enhances。
【解决方案2】:

解决方案 1:

c = [c for c in df.columns if len(set(df[c])) == 1]
print (c)

['B', 'C']

解决方案 2:

c = df.columns[df.eq(df.iloc[0]).all()].tolist()
print (c)
['B', 'C']

解决方案 2 的说明

首先将所有行与DataFrame.eq的第一行进行比较...

print (df.eq(df.iloc[0]))
       A     B     C      D
0   True  True  True   True
1  False  True  True  False
2  False  True  True  False

...然后检查每一列都是Trues 和DataFrame.all...

print (df.eq(df.iloc[0]).all())
A    False
B     True
C     True
D    False
dtype: bool

...最后过滤结果为 True 的列名:

print (df.columns[df.eq(df.iloc[0]).all()])
Index(['B', 'C'], dtype='object')

时间安排

np.random.seed(100)
df = pd.DataFrame(np.random.randint(10, size=(1000,100)))

df[np.random.randint(100, size=20)] = 100
print (df)

# Solution 1 (second-fastest):
In [243]: %timeit ([c for c in df.columns if len(set(df[c])) == 1])
3.59 ms ± 43.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

# Solution 2 (fastest):
In [244]: %timeit df.columns[df.eq(df.iloc[0]).all()].tolist()
1.62 ms ± 13.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

#Mohamed Thasin ah solution
In [245]: %timeit ([col for col in df.columns if len(df[col].unique())==1])
6.8 ms ± 352 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

#jpp solution
In [246]: %%timeit
     ...: vals = df.apply(set, axis=0)
     ...: res = vals[vals.map(len) == 1].index
     ...: 
5.59 ms ± 64.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

#smci solution 1
In [275]: %timeit df.columns[ df.nunique()==1 ]
11 ms ± 105 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

#smci solution 2
In [276]: %timeit [col for col in df.columns if not df[col].is_unique]
9.25 ms ± 80 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

#smci solution 3
In [277]: %timeit df.columns[ df.apply(lambda col: not col.is_unique) ]
11.1 ms ± 511 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

【讨论】:

  • @smci - 谢谢。
  • 我会提防声称 len(set(df[c])) 通常比原生 pandas len(df[col].unique()) 快,这个玩具示例只有 3 个值。在更大的df上试试。 set(df[c]) 如果用于大字符串或分类列,可能会耗尽内存。
  • @smci - 在更大的 DataFrame 中测试,pd.DataFrame(np.random.randint(10, size=(1000,100)))
  • 和 len(set(...)) 还是更快?你能发布时间吗?
  • @smci - 我的时间仅适用于较大的数据帧,而不适用于示例 OP 数据。
【解决方案3】:

试试这个,

print [col for col in df.columns if len(df[col].unique())==1]

输出:

['B', 'C']

【讨论】:

【解决方案4】:

您可以使用set 并对系列应用过滤器:

vals = df.apply(set, axis=0)
res = vals[vals.map(len) == 1].index

print(res)

Index(['B', 'C'], dtype='object')

如果列表输出很重要,请使用res.tolist()

【讨论】:

    猜你喜欢
    • 2021-12-13
    • 1970-01-01
    • 1970-01-01
    • 2020-06-09
    • 2019-07-22
    • 2014-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多