Подмножество и вычисление цикла для каждого столбца в dplyr

#r #dplyr #tidyverse

#r #dplyr #tidyverse

Вопрос:

У меня есть фрейм данных со значениями для 50 идентификаторов, повторяющихся в течение 10 итераций. Я хотел бы подмножество по идентификатору, а затем выполнить вычисления и повторить это для каждого столбца от x1 до x5 . Я использовал цикл for, но он очень неэффективен (мой фактический набор данных имеет намного больше идентификаторов).

Вот вычисления, которые я хотел бы выполнить. У меня был переменный успех с преобразованием в dplyr:

  1. Первое вычисление дает мне правильное значение для x1 , но необходимо повторить для каждого столбца от x1 до x5 .
 V1.x1 <- preds.df %>%
  split(.$ID) %>%
  sapply(function(ID) {
    (ID$x1 - mean(ID$x1))^2 # for X1 only
  }) %>%
  mean()
  
  1. Другое вычисление, которое включает вычитание из соответствующего значения в другом df data.pop . Моя попытка dplyr неверна даже для всего x1 :
 ## This is what I want to achieve, which I implemented using for-loop: 
# df for for-loop
Bsq.perID <- data.frame(matrix(NA, 
                               nrow = nrow(data.pop),     # 50 observations
                               ncol = 5)                  # 5 models
                        
# For-loop:
for (ids in 1:nrow(data.pop)){
  current.ID <- preds.df[preds.df$ID == ids, ]  # get current ID over all 10 iterations
  
  for (i in 1:5){
    Bsq.perID[ids, i] <- (mean(current.ID[, i]) - data.pop[ids, "real.val"])^2 
  }
  
}
Bsq.values <- colMeans(Bsq.perID)

## My wrong dplyr attempt of the above:
B1.x1 <- preds.df %>%
  split(.$ID) %>%
  sapply(function(ID) {
    (mean(ID$x1) - data.pop$real.val)^2 
  }) %>%
  mean()
  

Структура preds.df выглядит следующим образом:

 head(preds.df)
  
          x1          x2        x3        x4        x5 iteration          ID
1 20.005984  6.78242996  3.526411 21.463892  8.792720         1           1
2  2.890490  7.28232755 18.670470  6.717213 19.830930         1           2
3  4.868658 24.88117301  1.883913  3.897779 14.371414         1           3
4  6.495532  5.79591685  7.745554 20.153269  7.935672         1           4
5 19.297779  0.05068784 21.744816 14.957751 14.232126         1           5
6  7.090456 22.06322779  8.388263 10.672151  9.921884         1           6
  
 tail(preds.df)
  
            x1         x2         x3        x4        x5 iteration          ID
495 16.306927  2.8873609  9.7764755 23.798867 10.246443        10          45
496  4.767296 23.2086303  8.8394391  7.806442 24.898483        10          46
497 19.966301 13.7151699 10.2483011 15.199162  9.658736        10          47
498 18.134534 22.1658901  5.6481757 18.501411 23.787457        10          48
499  7.877636  7.2356274  8.2862336  3.790823 11.610848        10          49
500  8.554774  0.9199501  0.9650191 17.155611  1.158619        10          50
  

Комментарии:

1. Можете ли вы опубликовать данные, которые вы используете?

2. Да, пожалуйста, найдите его здесь drive.google.com/drive/folders /…

Ответ №1:

Я бы подошел к этому так:

 library(dplyr)
library(rio)
preds.df <- import("~/Downloads/preds.df.csv")
data.pop <- import("~/Downloads/data.pop.csv")
## added a row because data.pop is only 49 rows in the data you sent
data.pop <- bind_rows(data.pop, data.pop[1,])
  

Для этого можно использовать dplyr with mutate() :

 dat1 <- preds.df %>% 
  group_by(ID) %>% 
  mutate(across(x1:x5, function(x)(x-mean(x))^2))
  

Затем для второй части вы можете объединить данные

 data.pop <- data.pop %>% 
  mutate(ID = 1:n())

dat2 <- dat1 %>% left_join(data.pop)
  

Затем суммируйте по идентификатору, чтобы вычислить среднее значение x1 с x5 точностью ID до, затем из каждого вы можете вычесть real.val и возвести в квадрат.

 dat2 <- dat2 %>% 
  select(c(ID, x1:x5, real.val)) %>% 
  group_by(ID) %>% 
  mutate(across(x1:x5, function(x)(x-real.val)^2)) %>% 
  summarise_all(mean) %>% 
  select(-real.val)
  

Комментарии:

1. Часть 1 сработала. Спасибо! Что касается второго, то при удалении summarise_all(mean) я получаю ответы, которые близки, но все еще не верны. Моя цель состоит в том, чтобы для каждого столбца взять среднее значение x для каждого идентификатора по итерациям, затем вычесть это среднее значение из real.val этого идентификатора и возвести его в квадрат. Повторите для всех идентификаторов, всех 5 столбцов. Затем используйте colMeans() для возврата 5 значений в конце. В основном я вычисляю смещение ^ 2 для каждой модели здесь.

2. После дальнейшей проверки я понял, что все работает правильно до тех пор, пока summarise_all(mean) ошибка не заключается в вычитании соответствующих идентификаторов real.val из каждого значения.

3. @fluent, если вы поменяете местами инструкции summarise_all и mutate, которые должны это сделать. То, что происходило выше, заключалось в том, что он получал среднее значение, а затем вычитал real.val из среднего и возводил в квадрат, а не наоборот.