检查数据框列中的所有值是不是相同

Posted

技术标签:

【中文标题】检查数据框列中的所有值是不是相同【英文标题】:Check if all values in dataframe column are the same检查数据框列中的所有值是否相同 【发布时间】:2019-06-21 16:11:38 【问题描述】:

我想快速简单地检查 counts 的所有列值是否在数据框中都相同:

在:

import pandas as pd

d = 'names': ['Jim', 'Ted', 'Mal', 'Ted'], 'counts': [3, 4, 3, 3]
pd.DataFrame(data=d)

输出:

  names  counts
0   Jim       3
1   Ted       4
2   Mal       3
3   Ted       3

我只想要一个简单的条件,即if all counts = same value 然后是print('True')

有没有快速的方法来做到这一点?

【问题讨论】:

if len(df['counts'].unique()) ==1: print(True)怎么样 df.counts.nunique() == 1? 相关:Check if all elements in a list are identical df.counts.drop_duplicates().shape[0] ==1 【参考方案1】:

一种有效的方法是将第一个值与其余值进行比较,并使用all

def is_unique(s):
    a = s.to_numpy() # s.values (pandas<0.24)
    return (a[0] == a).all()

is_unique(df['counts'])
# False

虽然最直观的想法可能是计算unique 值的数量并检查是否只有一个,但这对于我们正在尝试做的事情来说会产生不必要的高复杂性。 Numpy 的 np.unique,由 pandas 的 nunique 调用,实现了底层数组的排序,其使用 quicksort(默认)具有 O(n·log(n)) 的估计复杂度。上面的做法是O(n)

当我们将其应用于整个数据帧时,性能差异变得更加明显(见下文)。


对于整个数据框

如果想对整个数据帧执行相同的任务,我们可以通过在all 中设置axis=0 来扩展上述内容:

def unique_cols(df):
    a = df.to_numpy() # df.values (pandas<0.24)
    return (a[0] == a).all(0)

对于共享示例,我们会得到:

unique_cols(df)
# array([False, False])

这是上述方法与其他一些方法(例如使用nunique(对于pd.Series)的比较)的基准:

s_num = pd.Series(np.random.randint(0, 1_000, 1_100_000))

perfplot.show(
    setup=lambda n: s_num.iloc[:int(n)], 

    kernels=[
        lambda s: s.nunique() == 1,
        lambda s: is_unique(s)
    ],

    labels=['nunique', 'first_vs_rest'],
    n_range=[2**k for k in range(0, 20)],
    xlabel='N'
)


以下是 pd.DataFrame 的时间安排。让我们也与numba 方法进行比较,这在这里特别有用,因为我们可以在给定列中看到重复值时立即利用捷径(注意:numba 方法仅适用于数字数据):

from numba import njit

@njit
def unique_cols_nb(a):
    n_cols = a.shape[1]
    out = np.zeros(n_cols, dtype=np.int32)
    for i in range(n_cols):
        init = a[0, i]
        for j in a[1:, i]:
            if j != init:
                break
        else:
            out[i] = 1
    return out

如果我们比较这三种方法:

df = pd.DataFrame(np.concatenate([np.random.randint(0, 1_000, (500_000, 200)), 
                                  np.zeros((500_000, 10))], axis=1))

perfplot.show(
    setup=lambda n: df.iloc[:int(n),:], 

    kernels=[
        lambda df: (df.nunique(0) == 1).values,
        lambda df: unique_cols_nb(df.values).astype(bool),
        lambda df: unique_cols(df) 
    ],

    labels=['nunique', 'unique_cols_nb', 'unique_cols'],
    n_range=[2**k for k in range(0, 20)],
    xlabel='N'
)

【讨论】:

我们可以检查是否没有。列中唯一值的个数为 1。 查找唯一值具有不必要的高复杂性来检查这一点。它包含在性能图中以明确@AnupamKumar 你说得对,我完全忘记了性能。【参考方案2】:

使用np.unique更新

len(np.unique(df.counts))==1
False

或者

len(set(df.counts.tolist()))==1

或者

df.counts.eq(df.counts.iloc[0]).all()
False

或者

df.counts.std()==0
False

【讨论】:

这个:df.counts.is_unique - 对我不起作用,但 df.counts.nunique() == 1 有效。我在 Windows 上运行 python 2.7。 @MEdwin 我的意思是你的熊猫版本。 我的熊猫版本是:0.23.4 @MEdwin 检查链接pandas.pydata.org/pandas-docs/stable/reference/api/…,如果仍然返回错误,请在github中提交错误 错误答案:is_unique 检查列中的值是否唯一,即没有重复。所要求的是检查列中的所有值是否相同,这是完全不同的。【参考方案3】:

我认为nunique 做了很多不必要的工作。迭代可以在第一个差异处停止。这个简单通用的解决方案使用itertools

import itertools

def all_equal(iterable):
    "Returns True if all elements are equal to each other"
    g = itertools.groupby(iterable)
    return next(g, True) and not next(g, False)

all_equal(df.counts)

甚至可以使用它一次性找到具有恒定内容的所有列:

constant_columns = df.columns[df.apply(all_equal)]

一个更易读但性能较差的替代方案:

df.counts.min() == df.counts.max()

如有必要,请在此处添加skipna=False

【讨论】:

【参考方案4】:

我更喜欢:

df['counts'].eq(df['counts'].iloc[0]).all()

我发现它最容易阅读,并且适用于所有值类型。根据我的经验,我也发现它足够快。

【讨论】:

很高兴解释为什么这种方法比另一种方法更可取。 添加说明。 警告:如果 df['counts'] 全部为 None,这将返回 False。

以上是关于检查数据框列中的所有值是不是相同的主要内容,如果未能解决你的问题,请参考以下文章

如何在其他四个数据框的列中检查一个数据框列是不是可用?

如何检查numpy矩阵的列中的所有值是不是相同?

检查列表中的单词并在 pandas 数据框列中删除这些单词

通过引用字符串位置检查数据框列中的子字符串

检查数组中的所有值是不是都存在于数据库列中

如何编写 R 脚本来检查直线;即,对于任何给定的行,一组列中的所有值是不是具有相同的值