Я моделирую некоторые данные и пытаюсь построить различные их образцы, используя plotly
и ipythonwidgets
. Я создал раскрывающиеся списки, чтобы люди могли выбирать размер выборки и количество выборок, которые они хотят собрать из распределения населения, сгенерированного с помощью этого:
from random import seed
from numpy.random import normal, negative_binomial, binomial
import pandas as pd
population_N = 1000000
population_data = pd.DataFrame({
"data.normal": normal(0, 1, population_N),
"data.poisson": negative_binomial(1, 0.5, population_N),
"data.binomial": binomial(1, 0.5, population_N)
})
Для их выборки (с условием или без него) и усреднения по выборке для нескольких выборок я создал следующую функцию:
def custom_simple(df, sample_size, type = "random"):
"""
Description
----
Take the population data.frame and generate a sample with a specific sample size
Parameters
----
df(pd.DataFrame): the population dataset
sample_size(int): the number of rows in the sample
type(str): if random, pull a random sample
Returns
----
sample(pd.DataFrame)
"""
if type == "random":
single = df.sample(sample_size)
else:
condition = df["data.normal"] < 1
single = df[condition].sample(sample_size)
return sample
def mean_samples(df, sample_size, type = "random", num = 1):
"""
Description
----
Take each sample and calculate the mean for each variable in the sample
Parameters
----
df(pd.DataFrame): the population dataset
sample_size(int): the number of rows in the dataset
type(str): if random, then do random sample
num(int): number of samples to take
Returns
----
sample_means(pd.DataFrame)
"""
sample_means = pd.DataFrame()
def repeated_sample(df, sample_size, type = type, num = num):
"""
Description:
----
Take the population dataset and come up with a specified number of samples
Parameters
----
df(pd.DataFrame): the population dataset
sample_size(int): the number of rows in the dataset
type(str): if random, then randomly sample
num(int): the number of samples to generate
Returns
----
sample_list(list(pd.DataFrame)): a list of samples stored as DataFrames
"""
sample_list = [custom_simple(df, sample_size, type) for n in range(num)]
return sample_list
raw_samples = repeated_sample(df, sample_size, type = type, num = num)
for i in raw_samples:
sample_mans = pd.concat([sample_means, i.mean(axis = 0).to_frame().T])
return sample_means
По сути, эти функции берут объект population_data
dataframe, используют pd.DataFrame.sample()
для передачи различных размеров выборки, а затем повторяют эти выборки для последующего усреднения.
Я выполняю эту функцию с циклом for, в котором хранится элемент словаря, представляющий собой среднее значение столбца для каждого размера выборки для каждого номера выборки:
sample_data = {}
sample_sizes = [20, 50, 100, 200, 500, 1000, 2000]
num_of_samples = [1, 2, 5, 10, 20, 50, 100]
for j in num_of_samples:
for i in sample_sizes:
sample_data['size_{}_sample_{}'.format(i,j)] = mean_samples(df = population_data, sample_size = i, type = "random", num = j)
sample_data["population_data"] = population_data
Затем я создаю функцию, которая использует ipython.widgets.Dropdown
, чтобы предоставить мне раскрывающийся список для различных образцов и количества образцов, которые должны подключаться к одному из объектов dict
в sample_data
. Функция также содержит информацию для передачи выбранного dict
объекта в графическую гистограмму.
def samples_histogram(dict, variable, type = "random"):
sample_widget = widgets.Dropdown(
options = ["20", "50", "100", "200", "500", "1000", "2000"],
value = "100",
description = "Sample size:"
)
sampling_widget = widgets.Dropdown(
options = ["2", "5", "10", "20", "50", "100"],
value = "2",
description = "# of samples"
)
trace = go.Histogram(x = dict.get("population_data")[variable])
fig = go.FigureWidget(data = trace)
def response(change):
if sample_widget.value == "20" and sampling_widget.value == "2":
temp_df = dict.get("size_20_sample_1")
temp_df = list(dict.items())
temp_df = temp_df[temp_df[0]=='size_20_sample_1'][1]
with fig.batch_update():
fig.data = [temp_df[variable].tolist()]
sample_widget.observe(response, names = "value")
sampling_widget.observe(response, names = "value")
box = widgets.VBox([
sample_widget,
sampling_widget,
fig
])
display(box)
Проблема, с которой я сталкиваюсь, заключается в том, что объект dict
, который я передаю, даже когда я конвертирую его в список (см. эту строку):
with fig.batch_update():
fig.data = [temp_df[variable].tolist()]
Это дает мне эту ошибку:
ValueError: The data property of a figure may only be assigned
a list or tuple that contains a permutation of a subset of itself.
Received element value of type <class 'list'>
Я не уверен, есть ли способ преобразовать объекты, которые я передаю, чтобы лучше играть с сюжетом, или я просто что-то упускаю.
Если я правильно понимаю, вы хотите обновить график, но то, как вы обновляете рисунок, неверно. fig.data
является объектом plotly.graph_objs._histogram.Histogram
. Чтобы изменить гистограмму, вам нужно изменить ее атрибут x
.
Пытаться
fig.data[0].x = temp_df[variable].tolist()
Также в вашем коде много опечаток. Попробуйте заменить simple
на sample
и sample_mans
на sample_means
. Отступ тоже неверный
def response(change):
if sample_widget.value == "20" and sampling_widget.value == "2":
temp_df = dict.get("size_20_sample_1")
temp_df = list(dict.items())
temp_df = temp_df[temp_df[0]=='size_20_sample_1'][1]
with fig.batch_update():
fig.data = [temp_df[variable].tolist()]
Кому (Действительно только при ссылке sample_widget.value == "20" and sampling_widget.value == "2"
)
def response(change):
if sample_widget.value == "20" and sampling_widget.value == "2":
temp_df = dict.get("size_20_sample_1")
temp_df = list(dict.items())
temp_df = temp_df[temp_df[0]=='size_20_sample_1'][1]
with fig.batch_update():
fig.data[0].x = temp_df[variable].tolist()
Вы пробовали
fig.add_trace([your_list_here])
?