Двойной цикл для заполнения фрейма данных - как исправить «недопустимую функцию в сложном назначении» - PullRequest
2 голосов
/ 11 апреля 2019

У меня есть датафрейм:

results 2 (612 obs. 281 variables)
ID Q1000_p2000_2016 Q1893_p2039_2016 .... Q1000_p2000_2017 Q1893_p2039_2017
1      392               381                    422              351
2      432               293                    398              310
.       .                 .                      .                .
.       .                 .                      .                .

, если есть 140 вопросов из 2016 года и 140 из 2017 года, каждый год вопросы имеют одно и то же имя, но каждое имя переменной имеет "_2016" или "_2017" в конце, чтобы различать периоды времени.

и другой фрейм данных:

absdiff (0 obs. 141 variables)
ID Q1000_p2000 Q1893_p2039 .... 

Я хочу присвоить значение в absdiff, взяв абсолютную разницу двух лет, для каждого вопроса для каждого ID.

В моем состоянии я проверяю, соответствует ли номер вопроса на 2016 год (или первые несколько символов имени переменной) номеру вопроса на 2017 в результатах2.

Если это так, я хочу присвоить абсолютную разницу двух ответов соответствующей переменной / номеру вопроса в absdiff

Я использовал

for (q in 2:141){
  if (substr(colnames(results2[q]),1,12) == substr(colnames(results2[q+140]),1,12)){
    for (j in 1:nrow(results2)){absdiff$substr(colnames(results2[q]),1,11) <- abs(results2[j,q] - results2[j,(q+140)])}
  }
  else 
    print("ERROR")
}

но я получаю это сообщение об ошибке:

Ошибка в absdiff $ substr (имена столбцов (результаты2 [q]), 1, 11) <- abs (результаты2 [j,: неверная функция в сложном назначении </p>

Какая проблема вызывает это сообщение об ошибке? Как мне это исправить?

Ради репликации все это можно упростить до:

ID <- c(1,2)
Q1000_p2000_2016 <- c(392,432)
Q1893_p2039_2016 <- c(381,293)
Q1000_p2000_2017 <- c(422,398)
Q1893_p2039_2017 <- c(351,310)    

results2 <- as.data.frame(cbind(ID, Q1000_p2000_2016, Q1893_p2039_2016 ,Q1000_p2000_2017, Q1893_p2039_2017 ))

absdiff <- results2[FALSE,1:3]

    for (q in 2:3){
  if (substr(colnames(results2[q]),1,12) == substr(colnames(results2[q+2]),1,12)){
    for (j in 1:nrow(results2)){absdiff$substr(colnames(results2[q]),1,11) <- abs(results2[j,q] - results2[j,(q+2)])}
  }
  else 
    print("ERROR")
}

Ответы [ 2 ]

5 голосов
/ 11 апреля 2019

Не используйте петли, а просто векторизуйте.Получите столбцы 2016 года, столбцы 2017 года и затем вычтите:

col2016<-grep("_2016$",names(results2),value=TRUE)
col2017<-grep("_2017$",names(results2),value=TRUE)
absdiff<-results2[,col2017]-results2[,col2016]
#  Q1000_p2000_2017 Q1893_p2039_2017
#1               30              -30
#2              -34               17

Чтобы сохранить столбец ID, просто добавьте его после:

absdiff$ID<-results2$ID
2 голосов
/ 11 апреля 2019

Быстрые примечания к вашему коду для будущего кодирования: причина ошибки здесь следующая: absdiff$substr(colnames(results2[q]),1,11), поскольку вы не можете использовать знак доллара с функцией только потому, что она возвращает строку, вы можете использовать скобки для нарезки как это absdiff[substr(colnames(results2[q]),1,11)].

Другая проблема с кодом заключается в том, что absdiff изначально пуст при вызове results2[FALSE,1:3], вы получаете имена столбцов, но не строки (если вы хотите удалить все строки FALSE), что означает, что вы выиграли не сможет дать значения новому столбцу.

И, наконец, если вы считаете, что в будущем вам может понадобиться больше подобных вещей, я бы порекомендовал вам взглянуть на Tidy Data и на различные методы, которые вы можете использовать для преобразования данных в сделать анализ более простым и интуитивно понятным, например, на примере данных вы можете сделать что-то вроде этого:

library(dplyr)
library(reshape2)
new_resutls  <- results2 %>% 
  reshape2::melt(id.vars='ID') %>% 
  dplyr::mutate(question = substr(variable, 1, 11), 
                year = substr(variable, 13, 16))
new_resutls

#   ID         variable value    question year
# 1  1 Q1000_p2000_2016   392 Q1000_p2000 2016
# 2  2 Q1000_p2000_2016   432 Q1000_p2000 2016
# 3  1 Q1893_p2039_2016   381 Q1893_p2039 2016
# 4  2 Q1893_p2039_2016   293 Q1893_p2039 2016
# 5  1 Q1000_p2000_2017   422 Q1000_p2000 2017
# 6  2 Q1000_p2000_2017   398 Q1000_p2000 2017
# 7  1 Q1893_p2039_2017   351 Q1893_p2039 2017
# 8  2 Q1893_p2039_2017   310 Q1893_p2039 2017

Ваша проблема может быть решена следующим образом:

new_resutls %>% 
  dplyr::group_by(ID, question) %>% 
  dplyr::summarise(absdiff = abs(sum(value*c(1, -1))))

#      ID question    absdiff
#   <dbl> <chr>         <dbl>
# 1     1 Q1000_p2000      30
# 2     1 Q1893_p2039      30
# 3     2 Q1000_p2000      34
# 4     2 Q1893_p2039      17
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...