Понимание роли перемешивания в np.random.Generator.choice()

В документации к функции numpy random.Generator.choice одним из аргументов является shuffle, который по умолчанию равен True.

В документации указано:

перетасовать bool, необязательно

Перетасовывается ли выборка при выборке без замены. По умолчанию установлено значение True, False обеспечивает ускорение.

Мне недостаточно информации, чтобы понять, что это значит. Я не понимаю, зачем нам перетасовывать, если это уже достаточно случайно, и я не понимаю, почему мне будет предоставлена ​​возможность не перетасовывать, если это приведет к предвзятой выборке.

Если я установлю shuffle на False, получу ли я случайную (независимую) выборку? Мне также хотелось бы понять, почему мне вообще нужна настройка по умолчанию True.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
3
0
78
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы по-прежнему получаете случайный выбор независимо от вашего выбора shuffle. Однако если вы выберете shuffle=False, порядок вывода не зависит от порядка ввода.

Это легче всего увидеть, когда количество выбранных элементов равно общему количеству элементов:

import numpy as np
rng = np.random.default_rng()
x = np.arange(10)
rng.choice(x, 10, replace=False, shuffle=False)
# array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
rng.choice(x, 10, replace=False, shuffle=True)
# array([8, 1, 3, 9, 6, 5, 0, 7, 4, 2])

Если вы уменьшите количество выбранных элементов и используете shuffle=False, вы сможете убедиться, что недостающие элементы распределены должным образом.

import numpy as np
import matplotlib.pyplot as plt
rng = np.random.default_rng()
x = np.arange(10)
set_x = set(x)
missing = []
for i in range(10000):
    # By default, all `p` are equal, so which item is
    # missing should be uniformly distributed
    y = rng.choice(x, 9, replace=False, shuffle=False)
    set_y = set(y)
    missing.append(set_x.difference(set_y).pop())
plt.hist(missing)

Но вы увидите, что элементы, которые появлялись раньше в x, как правило, появляются раньше в выводе, и наоборот. То есть порядок ввода и вывода коррелирует.

x = np.arange(10)
correlations = []
for i in range(10000):
    y = rng.choice(x, 9, replace=False, shuffle=False)
    correlations.append(stats.spearmanr(np.arange(9), y).statistic)
plt.hist(correlations)

Если это подходит для вашего приложения, смело устанавливайте shuffle=False для ускорения.

%timeit rng.choice(10000, 5000, replace=False, shuffle=True)
# 187 µs ± 26.9 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit rng.choice(10000, 5000, replace=False, shuffle=False)
# 146 µs ± 18.4 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Чем больше элементов необходимо выбрать, тем более выражено ускорение.

%timeit rng.choice(10000, 1, replace=False, shuffle=True)
# 17.6 µs ± 3.64 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit rng.choice(10000, 1, replace=False, shuffle=False)
# 16.5 µs ± 2.47 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)

против

%timeit rng.choice(10000, 9999, replace=False, shuffle=True)
# 214 µs ± 32.7 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit rng.choice(10000, 9999, replace=False, shuffle=False)
# 124 µs ± 27.5 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Поскольку @matt-haberland уже представил статистику, на случайность не влияет наличие или отсутствие перетасовки.

Однако на самом деле выбранные элементы одни и те же. Оператор assert в приведенном ниже коде не подведет.

import numpy as np

n = 1000
m = 100

for seed in range(1000):
    result_with_shuffle = np.random.default_rng(seed).choice(range(n), size=m, replace=False, shuffle=True)
    result_without_shuffle = np.random.default_rng(seed).choice(range(n), size=m, replace=False, shuffle=False)
    assert list(result_with_shuffle) != list(result_without_shuffle)
    assert set(result_with_shuffle) == set(result_without_shuffle)

Кроме того, как упоминал @matt-haberland, самый простой способ увидеть, что порядок вывода не зависит (или нет) от порядка ввода, - это выбрать то же количество элементов, что и входные данные, но вы должны осознавая, что некоторые тенденции проявятся даже при гораздо меньших размерах.

import matplotlib.pyplot as plt
import numpy as np

n = 10000
m = 2000
seed = 0

sample_with_shuffle = np.random.default_rng(seed).choice(range(n), size=m, replace=False, shuffle=True)
sample_without_shuffle = np.random.default_rng(seed).choice(range(n), size=m, replace=False, shuffle=False)


def plot(sample, title, index):
    plt.subplot(1, 2, index)
    plt.bar(range(m), sample)
    plt.title(title)
    plt.xlabel("Index")
    plt.ylabel("Value")


plt.figure(figsize=(14, 6))
plot(sample_with_shuffle, "shuffle=True", 1)
plot(sample_without_shuffle, "shuffle=False", 2)
plt.tight_layout()
plt.show()

Хотя выборка без перетасовки кажется случайной, если мы посмотрим на первые пару значений, на графике четко видна восходящая тенденция слева направо.

Таким образом, если порядок выходов имеет значение, вам всегда следует перетасовывать их. В противном случае нет никакого преимущества.

Другие вопросы по теме