#python #numpy
#python #pandas #numpy #Статистика #наука о данных
Вопрос:
У меня есть следующие значения, которые описывают набор данных:
Number of Samples: 5388
Mean: 4173
Median: 4072
1st Decile: 2720
9th Decile: 5676
Мне нужно сгенерировать любые наборы данных, которые будут соответствовать этим значениям.
Все примеры, которые я нашел, требуют, чтобы у вас было стандартное отклонение, которого у меня нет.
Как это можно сделать?
Спасибо!
Ответ №1:
Интересный вопрос! Основываясь на предложениях Скотта, я быстро попробовал это сделать.
Входные данные:
import random
import pandas as pd
import numpy as np
# fixing the random seed
random.seed(a=1, version=2)
# formating floats
pd.options.display.float_format = '{:.1f}'.format
# given inputs
count = 5388
mean = 4173
median = 4072
lower_percentile = 10
lower_percentile_value = 2720
upper_percentile = 90
upper_percentile_value = 5676
max_value = 6325
min_value = 2101
Функция:
def generate_dataset(count, mean, median, lower_percentile, upper_percentile,
lower_percentile_value, upper_percentile_value,
min_value, max_value
):
# Calculate the number of values that fall within each percentile
p_1_size = int(float(lower_percentile) * float(count) / 100)
p_4_size = int(count - (float(upper_percentile) * float(count) / 100))
p_2_size = int((count / 2) - p_1_size)
p_3_size = int((count / 2) - p_4_size)
# can be used to adjust the mean
mean_adjuster = 5790
# randomly pick values of right size from a range
p_1 = random.choices(range(min_value, lower_percentile_value), k=p_1_size)
p_2 = random.choices(range(lower_percentile_value, median), k=p_2_size)
p_3 = random.choices(range(median, mean_adjuster), k=p_3_size)
p_4 = random.choices(range(upper_percentile_value, max_value), k=p_4_size)
return p_1 p_2 p_3 p_4
dataset = generate_dataset(
count, mean, median, lower_percentile, upper_percentile,
lower_percentile_value, upper_percentile_value, min_value, max_value
)
Comparaison:
# converting into DataFrame
df = pd.DataFrame({"x": dataset})
new_count = len(df)
new_mean = np.mean(df.x)
new_median = np.quantile(df.x, 0.5)
new_lower_percentile = np.quantile(df.x, lower_percentile/100)
new_upper_percentile = np.quantile(df.x, upper_percentile/100)
compare = pd.DataFrame(
{
"value": ["count", "mean", "median", "low_p", "high_p"],
"original": [count, mean, median, lower_percentile_value, upper_percentile_value],
"new":[new_count, new_mean, new_median, new_lower_percentile, new_upper_percentile]
}
)
print(compare)
Вывод:
value original new
0 count 5388 5388.0
1 mean 4173 4173.4
2 median 4072 4072.5
3 low_p 2720 2720.4
4 high_p 5676 5743.0
Добиться точного равенства значений немного сложно, когда все ваши значения являются целыми числами, а не числами с плавающей запятой..
Вы можете добавить другую переменную для управления средним с помощью двух чисел или изменить случайное начальное значение и посмотреть, сможете ли вы получить более близкие значения. В качестве альтернативы вы можете написать функцию, которая изменяет начальное значение до тех пор, пока значения не станут равными. (может занять пару минут или пару столетий:)
Приветствия!
Комментарии:
1. Привет, есть ли какой-нибудь способ сделать то же самое, но вместо этого с 25-м и 75-м процентилями? Спасибо!
2. Привет, @433MEA, я отредактировал ответ, чтобы работать со всеми процентилями. Ваше здоровье!
Ответ №2:
Медиана фиксирует 5388/2 ~ 2694-е и 5388/2 1 ~ 2695-е значения (средние значения). Итак, давайте просто сделаем эти оба значения 4072. 1-й и 9-й децили исправляют 5388/10 ~ 538,8-е и 9 * 5388/10 ~ 4849,2-е значения. В моде множество формул для децилей, но было бы безопасно установить для 538-го и 539-го значений 2720. Аналогичным образом мы можем получить правильный 9-й дециль, зафиксировав 4849-е и 4850-е значения на 5676. Среднее значение обеспечивает на одну степень свободы меньше, но вычисление среднего включает в себя фактические значения из всего набора данных, поэтому мы отложим это на потом. Во-первых, что нам нужно сделать, это сделать 537 значений меньше 2719. (почти) Не имеет значения как, но было бы неплохо сделать их достаточно низкими (будет объяснено позже). Затем нам нужно сделать 2693-539 (количество значений между нашими фиксированными значениями первого дециля и фиксированными средними значениями) значениями между 2720 (первый дециль) и 4072 (медиана). Затем создайте 4848-2695 значений между 4072 и 5676. Теперь нам нужно 5388-4850 (общее количество значений минус 9-й дециль и более низкие значения) значений, превышающих 5676, но напомним, что нам также нужно установить среднее значение. Существует буквально бесконечное количество способов сделать это, но один из способов — просто сделать все значения выше 9-го дециля идентичными. Для этого мы можем вычислить среднее из нижних 4850 значений (которые у нас уже есть) и понять, что (5388-4850) * X 4850 * M = 4173, где M — среднее из нижних 4850 значений. Решите для X, чтобы получить нужное вам значение. Поскольку X должно быть больше 5676, полезно, если вы зададите значения ниже первого дециля малыми, потому что это дает нам некоторую свободу действий. Другой способ сделать это — выбрать случайные числа выше 5676 для всех этих значений, кроме одного, затем выбрать последнее значение таким образом, чтобы зафиксировать среднее (опять же, было бы разумно выбирать случайные значения не намного выше 5676, поскольку последнее оставшееся значение можно сделать сколь угодно большим, чтобы довести среднее значение до правильного значения).
В любом случае, в numpy
вы будете просто генерировать кучу случайных чисел. np.random.randint
работа должна быть выполнена.
Ответ №3:
Общий комментарий:
Если вы указали квантильную функцию Q (p), то выборка U в соответствии с равномерным распределением и включение Q (U) дает результат из желаемого распределения.