Как сделать выборку из совокупности так, чтобы выборка имела заданное распределение переменной?

Набор данных №1 (ds1) имеет особое распределение переменной «масса». Я хотел бы взять образец из набора данных № 2 (ds2) так, чтобы образец имел распределение переменной «масса», соответствующее распределению ds1. Это работает, когда «масса» в ds2 распределена равномерно, и я использую функцию kde из ds1 в качестве весов при выборке ds2 (используя Pandas: ds2.sample(...,weights = ds1_kde)). Однако, когда массовая переменная в ds2 распределена неравномерно, перекос всегда отражается в выборке kde, и распределение масс в выборке не отражает распределение масс ds1.

Это упрощенная версия проблемы, с которой я сталкиваюсь, когда делаю выборку из генеральной совокупности и пытаюсь контролировать распределение переменной так, чтобы она соответствовала распределению той же самой переменной в исследуемой мной подгруппе.

Подход работает (kde образца аналогичен kde ds1), когда распределение массы в ds2 равномерно:

import pandas as pd
import matplotlib as plt
import seaborn as sns
import numpy as np

# Dataset 1
ds1 = pd.DataFrame({'mass':[0,1,1,2,2,2,2,3,3,3,4,4,5,6,7,7,8,8,8,8,9,9,9,9,9,9,9,10,10,10,10,10,10,11,11,11,12,13,14,15]})

# Find kde of dataset 1
ds1_kde = stats.gaussian_kde(ds1.mass.to_list())
ds1_kde.set_bandwidth(bw_method=0.2)

# dataset 2 with a uniform distribution
ds2 = pd.DataFrame({'mass':[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]})
ds2['ds1_kde'] = ds2.mass.apply(lambda x: ds1_kde(x)[0])
smpl = ds2.sample(200, weights='ds1_kde',replace=True)

smpl_kde = stats.gaussian_kde(smpl.mass.to_list())
smpl_kde.set_bandwidth(bw_method=0.2)

bins = np.linspace(0, 16, 15)
fig = plt.figure()
xs=np.linspace(0,15,100)
sns.histplot(ds2.mass.to_list(),stat='density',bins=bins,color='blue',label='ds2',alpha=0.5)
sns.histplot(ds1.mass.to_list(),stat='density',bins=bins,color='orange',label='ds1 (goal distribution)',alpha=0.5)
sns.histplot(smpl.mass.to_list(),stat='density',bins=bins,color='green',label='sample from ds2',alpha=0.5)
sns.lineplot(x=xs,y=ds1_kde(xs),color='orange',label='ds1_kde')
sns.lineplot(x=xs,y=smpl_kde(xs),color='green',label='sample_kde')
plt.xlabel("mass")
plt.title("Success when mass distribution in ds2 is uniform")

Однако, когда масса в ds2 искажена, этот подход терпит неудачу:

# Dataset 2 with a non-uniform distribution
ds2 = pd.DataFrame({'mass':[0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,3,3,3,4,4,5,6,7,8,9,10,11,12,13,14,15]})

# Add dataset1 kde to dataset2 to use as weights when sampling
ds2['ds1_kde'] = ds2.mass.apply(lambda x: ds1_kde(x)[0])
smpl = ds2.sample(200, weights='ds1_kde',replace=True)

# Find kde of sample
smpl_kde = stats.gaussian_kde(smpl.mass.to_list())
smpl_kde.set_bandwidth(bw_method=0.2)

# Plot
bins = np.linspace(0, 16, 15)
fig = plt.figure()
xs = np.linspace(0,15,100)
sns.histplot(ds2.mass.to_list(),stat='density',bins=bins,color='blue',label='ds2',alpha=0.5)
sns.histplot(ds1.mass.to_list(),stat='density',bins=bins,color='orange',label='ds1 (goal distribution)',alpha=0.5)
sns.histplot(smpl.mass.to_list(),stat='density',bins=bins,color='green',label='sample from ds2',alpha=0.5)
sns.lineplot(x=xs,y=ds1_kde(xs),color='orange',label='ds1_kde')
sns.lineplot(x=xs,y=smpl_kde(xs),color='green',label='sample_kde')
plt.xlabel("mass")
plt.title("Failure when mass distribution in ds2 is skewed")

Неудачный пример сюжета.

Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
53
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Веса, используемые для выборки из ds2, можно скорректировать с учетом неравномерного распределения данных: weights=ds1_kde/ds2_kde, где ds1_kde — целевое распределение, а ds2_kde — распределение генеральной совокупности, из которой производится выборка.

# Find kde of dataset 2
ds2_kde = stats.gaussian_kde(ds2.mass.to_list())
ds2_kde.set_bandwidth(bw_method=0.2)

# Correct sampling weights using ds2_kde
ds2["ds2_kde"] = ds2.mass.apply(lambda x: ds2_kde(x)[0])
ds2["weights"] = ds2.ds1_kde/ds2.ds2_kde

# Draw a sample
smpl2 = ds2.sample(200, weights='weights',replace=True)

# Find kde of sample
smpl2_kde = stats.gaussian_kde(smpl2.mass.to_list())
smpl2_kde.set_bandwidth(bw_method=0.2)

# Plot
bins = np.linspace(0, 16, 15)
fig = plt.figure()
xs = np.linspace(0,15,100)
sns.histplot(ds2.mass.to_list(),stat='density',bins=bins,color='blue',label='ds2',alpha=0.5)
sns.histplot(ds1.mass.to_list(),stat='density',bins=bins,color='orange',label='ds1 (goal distribution)',alpha=0.5)
sns.histplot(smpl2.mass.to_list(),stat='density',bins=bins,color='green',label='sample from ds2',alpha=0.5)
sns.lineplot(x=xs,y=ds1_kde(xs),color='orange',label='ds1_kde')
sns.lineplot(x=xs,y=smpl2_kde(xs),color='green',label='sample_kde')
plt.xlabel("mass")
plt.title("Success when corrected for mass distribution in ds2")

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