Как сгенерировать набор данных на основе значений среднего, медианы, 1-го и 9-го децилей?

#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) дает результат из желаемого распределения.