Я хочу быстро и легко проверить, совпадают ли все значения столбцов для 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').
Есть ли быстрый способ сделать это?
df.counts.nunique() == 1?
Связано: Проверить, все ли элементы в списке идентичны
df.counts.drop_duplicates().shape[0] == 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's' np.unique, вызываемый pandas' nunique, реализует сортировку базовых массивов, которая имеет среднюю сложность O(n·log(n)) с использованием быстрая сортировка (по умолчанию). Вышеупомянутый подход — O(n).
Разница в производительности становится более очевидной, когда мы применяем это ко всему фрейму данных (см. ниже).
В случае, если вы хотите выполнить ту же задачу для всего фрейма данных, мы можем расширить вышеизложенное, установив axis=0 в all:
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
Вы правы, я совсем забыл о производительности.
Обновление с помощью 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 работает. Я использую Python 2.7 в Windows.
@MEdwin Я имею в виду твою версию панд.
Моя версия панд: 0.23.4
@MEdwin проверьте ссылку pandas.pydata.org/pandas-docs/stable/reference/api/…, если все еще возвращает ошибку, отправьте сообщение об ошибке в github.
Плохой ответ: is_unique проверяет уникальность значений в столбце, т. е. отсутствие дубликатов. То, что было задано, заключается в проверке того, что все значения в столбце одинаковы, а это совсем другое.
Я думаю, что 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, если необходимо.
Я предпочитаю:
df['counts'].eq(df['counts'].iloc[0]).all()
Я считаю, что его легче всего читать, и он работает со всеми типами значений. Я также нашел это достаточно быстро в моем опыте.
Было бы здорово объяснить, почему этот метод предпочтительнее другого.
Добавил объяснение.
Предупреждение: это вернет False, если df['counts'] будет равен None.
как насчет
if len(df['counts'].unique()) ==1: print(True)