Заменить значение средним на основе двух классов - PullRequest
0 голосов
/ 06 мая 2020

У меня есть dataset с 2 календарными переменными (Week & Hour) и 1 Amount переменная:

 Week Hour Amount
   35    1    367
   35    2    912
   36    1    813
   36    2    482
   37    1    112
   37    2    155
   35    1    182
   35    2    912
   36    1    551
   36    2    928
   37    1    125
   37    2    676

I wi sh для замены каждого значения Amount со средним значением для каждого наблюдения с той же парой неделя / час. Например, здесь есть 2 набл. для (Week=35, Hour=1), со значениями Amount 367 и 182. Следовательно, в этом примере в 2 строках с (Week=35, Hour=1) следует заменить Amount на mean(c(367,182). Окончательный результат должен быть:

Week Hour Amount
  35    1  274.5
  35    2  912.0
  36    1  682.0
  36    2  705.0
  37    1  118.5
  37    2  415.5
  35    1  274.5
  35    2  912.0
  36    1  682.0
  36    2  705.0
  37    1  118.5
  37    2  415.5

У меня есть следующий код, решающий эту проблему. Однако для полного набора данных с тысячами строк это очень медленно. Есть ли способ автоматически изменить форму с помощью этого парного средства?

dataset = data.frame(Week=c(35,35,36,36,37,37,35,35,36,36,37,37),
                     Hour = c(1,2,1,2,1,2,1,2,1,2,1,2),
                     Amount = c(367,912,813,482,112,155,182,912,551,928,125,676))

means <- reshape2::dcast(dataset, Week~Hour, value.var="Value", mean)

for (i in 1:nrow(dataset)) {
  print(i)
  dataset$Amount[i] <- means[means$Week==dataset$Week[i],which(colnames(means)==dataset$Hour[i])]
}

Ответы [ 3 ]

3 голосов
/ 06 мая 2020

Возможное решение с dplyr:

dataset %>% 
  group_by(Week, Hour) %>% 
  summarise(mean_amount = mean(Amount))

Вы группируете по неделям и часам и вычисляете среднее значение на основе этого условия.

EDIT

Чтобы сохранить исходную структуру (количество строк), измените код на

dataset %>% 
  group_by(Week, Hour) %>% 
  mutate(Amount = mean(Amount))
1 голос
/ 06 мая 2020

Если идея состоит в том, чтобы получить среднее значение Amount по Week и Hour, это будет работать:

aggregate(Amount ~ ., dataset, mean)
  Week Hour Amount
1   35    1  274.5
2   36    1  682.0
3   37    1  118.5
4   35    2  912.0
5   36    2  705.0
6   37    2  415.5

EDIT :

Если, однако, идея состоит в том, чтобы вернуть средние значения в dataset, тогда это должно сработать:

x <- aggregate(Amount ~ ., dataset, mean)
dataset$Amount <- x$Amount[match(apply(dataset[,1:2], 1, paste0, collapse = " "), 
                                 apply(x[,1:2], 1, paste0, collapse = " "))]
dataset
   Week Hour Amount
1    35    1  274.5
2    35    2  912.0
3    36    1  682.0
4    36    2  705.0
5    37    1  118.5
6    37    2  415.5
7    35    1  274.5
8    35    2  912.0
9    36    1  682.0
10   36    2  705.0
11   37    1  118.5
12   37    2  415.5

Пояснение:

Эти paste вместе в строки строки первых двух столбцов в средстве dataframe x и в dataset с использованием функции apply он использует match в этих строках для присвоения средних значений соответствующим строкам в dataset

РЕДАКТИРОВАТЬ 2 :

В качестве альтернативы вы можете использовать interaction и, соответственно, %in% для этого преобразования:

dataset$Amount <- x$Amount[match(interaction(dataset[,1:2]), interaction(x[,1:2]))]
# or:
dataset$Amount <- x$Amount[interaction(x[,1:2]) %in% interaction(dataset[,1:2])]
0 голосов
/ 07 мая 2020

Раствор Base R:

dataset$Amount <- with(dataset, ave(dataset$Amount, dataset$Week, dataset$Hour, FUN = mean))

Данные:

dataset = data.frame(Week=c(35,35,36,36,37,37,35,35,36,36,37,37),
                     Hour = c(1,2,1,2,1,2,1,2,1,2,1,2),
                     Amount = c(367,912,813,482,112,155,182,912,551,928,125,676))
...