Добавление нормального распределения к гистограмме в R - PullRequest
0 голосов
/ 29 октября 2018

Я хочу построить гистограмму и затем наложить ее на нормальное распределение, которое представляет распределение данных. Однако мои данные уже учтены:

df<- structure(list(trips = c(12955L, 36890L, 47035L, 48650L, 70910L, 
93755L, 45315L, 16565L, 4725L, 9460L), dist.km = c(0.5, 2, 4, 
8.5, 12.5, 17.5, 22.5, 27.5, 32.5, 42.5), share = c(0.03, 0.09, 
0.12, 0.13, 0.18, 0.24, 0.12, 0.04, 0.01, 0.02)), row.names = c(NA, 
-10L), class = c("tbl_df", "tbl", "data.frame"))

Поскольку данные уже подсчитаны, я могу использовать barplot вместо hist:

barplot(df$share, 
          names.arg=census.car$dist.km,
          col="orange", 
          xlab="km", 
          ylab="trips")

enter image description here

Два вопроса:

  1. Есть ли способ построить гистограмму напрямую вместо использования barplot в этом случае?
  2. Как я могу наложить эту гистограмму на линию нормального распределения, которая соответствует моим данным?

Ответы [ 2 ]

0 голосов
/ 29 октября 2018

Q1: если у вас нет исходных данных, вы не можете использовать hist.

Q2: с какой-то работой.

Во-первых, barplot не предоставляет дискретную ось X. Глядя на ваш график, это ясно показано, где интервал между первыми двумя столбцами (2-0,5 = 1,5) такой же, как последние два столбца (42,5-32,5 = 10). Вы можете получить средние точки оси X, посмотрев (невидимое) возвращаемое значение barplot:

(barplot(df$share, names.arg=df$dist.km,
         col="orange", xlab="km", ylab="trips"))
#       [,1]
#  [1,]  0.7
#  [2,]  1.9
#  [3,]  3.1
#  [4,]  4.3
#  [5,]  5.5
#  [6,]  6.7
#  [7,]  7.9
#  [8,]  9.1
#  [9,] 10.3
# [10,] 11.5

Точки равноудалены, несмотря на то, что действительные точки не делают этого. Это равное расстояние объясняется тем, что R фактически принимает категориальные данные, а не непрерывные.

Чтобы компенсировать это, мы можем либо отрегулировать ширину графиков, либо расстояние между ними. Если бы мы изменили ширину, то мы бы сравнили ширину с визуальной важностью, чего нам следует избегать, поэтому давайте перейдем к «пробелу»:

(bp <- barplot(df$share, names.arg=df$dist.km,
               space = c(0, diff(df$dist.km)),
               col="orange", xlab="km", ylab="trips"))
#       [,1]
#  [1,]  0.5
#  [2,]  3.0
#  [3,]  6.0
#  [4,] 11.5
#  [5,] 16.5
#  [6,] 22.5
#  [7,] 28.5
#  [8,] 34.5
#  [9,] 40.5
# [10,] 51.5

barplot adjusted for non-equi-distant spacing

Чтобы построить нормальную кривую, нам нужно среднее значение исходного распределения и стандартное отклонение. Без исходных данных мы можем аппроксимировать их средневзвешенным значением и средневзвешенным стандартным отклонением, оба из которых предоставлены пакетом Hmisc.

mu <- Hmisc::wtd.mean(df$dist.km, df$trips)
sigma <- sqrt(Hmisc::wtd.var(df$dist.km, weights = df$trips))
c(mu, sigma)
# [1] 13.565338  8.911899

К сожалению, как мы видим из выходных данных второго barplot выше, ось X не в том же масштабе, что и данные. К счастью, он все еще непрерывен и линейен для нас, поэтому нам просто нужно приспособиться к этому. Мы можем вычислить его вручную, но для удобства рассмотрим функцию обратного преобразования:

func <- function(a) {
  (min(df$dist.km) - bp[1,1]) + # the offset, happens to be 0 here since
                                # the first datapoint is exactly 0.5
    a * diff(range(bp[,1])) / diff(range(df$dist.km))
}

mu2 <- func(mu)
sigma2 <- sigma
c(mu2, sigma2)
# [1] 16.472196  8.911899

Обратите внимание, что мы не корректируем отклонение: напомним (из вашего класса статистики), что когда вы добавляете значение ко всем данным в источнике, статистика "местоположения" (например, среднее значение, медиана) корректируется аналогично (добавьте значение), но разница не изменилась.

Так что теперь мы можем использовать curve, чтобы добавить это к сюжету:

curve(dnorm(x, mean=mu2, sd=sigma2),
      col = "red", lwd = 2, add=TRUE)

barplot with un-scaled normal curve

Примечание: вызов функции, который мы дали в качестве первого аргумента curve, нуждается в переменной x, хотя мы ее не определили. Это используется внутри curve и заменяется фактическим вектором значений. Может быть другим, возможно с curve(dnorm(yy,...), xname="yy").

Эстетически это недостаточно высоко ... мы можем масштабировать его с максимальной частотой:

# start over
bp <- barplot(df$share, names.arg=df$dist.km,
              space = c(0, diff(df$dist.km)),
              col="orange", xlab="km", ylab="trips")
curve(dnorm(x, mean=mu2, sd=sigma2) / max(df$share),
      col = "red", lwd = 2, add=TRUE)

barplot with adjusted normal curve

Последняя точка: эта нормальная кривая является приближенной, и, хотя она хорошая, она все еще несовершенна. Если у вас есть исходные данные, было бы гораздо лучше использовать hist и фактические значения mu / sigma.

0 голосов
/ 29 октября 2018

Здесь у вас есть отличная ссылка для решения вашего вопроса:

Наложение нормальной кривой на гистограмму в R

Отвечая на ваши вопросы:

1 - Да, вы должны сделать dist.km и отключиться как 1 переменная, а затем вызвать функцию hist (), но с вашим форматом данных ваш путь довольно крутой.

2- Использование кривой () и линий (), как указано в ссылке.

...