web-dev-qa-db-fra.com

Vérifiez si toutes les valeurs de la colonne dataframe sont identiques

Je veux vérifier rapidement et facilement si toutes les valeurs de colonne pour counts sont les mêmes dans une trame de données:

Dans:

import pandas as pd

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

En dehors:

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

Je veux juste une condition simple que if all counts = same value Puis print('True').

Existe-t-il un moyen rapide de procéder?

15
HelloToEarth

Une façon efficace de le faire est de comparer la première valeur avec les autres et d'utiliser all :

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

is_unique(df['counts'])
# False

Pour une trame de données entière

Dans le cas où vous souhaitez effectuer la même tâche sur une trame de données entière, nous pouvons étendre ce qui précède en définissant axis=0 dans all:

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

Voici un point de référence des méthodes ci-dessus par rapport à d'autres approches, telles que l'utilisation de nunique (pour a 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'
)

enter image description here


Dans le cas d'un pd.DataFrame, une bonne option pourrait aussi être numba, d'autant plus que nous pouvons profiter du raccourci dès que nous voyons une valeur répétée dans une colonne donnée (cela ne fonctionnera qu'avec des données numériques):

from numba import njit

@njit
def unique_cols_nb(a):
    n_cols = a.shape[1]
    out = np.zeros(n_cols, dtype=np.int8)
    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

Si nous comparons les trois méthodes:

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'
)

enter image description here

20
yatu

Mettre à jour à l'aide de np.unique

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

Ou

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

Ou

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

Ou

df.counts.std()==0
False
4
YOBEN_S

Je pense que nunique fait beaucoup plus de travail que nécessaire. L'itération peut s'arrêter à la première différence. Cette solution simple et générique utilise 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)

On peut même l'utiliser pour trouver en une seule fois toutes colonnes avec un contenu constant:

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

Une alternative un peu plus lisible mais moins performante:

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

Ajouter skipna=False ici si nécessaire.

0
Michel de Ruiter