#r #loops #dataframe #for-loop
#r #циклы #фрейм данных #для цикла
Вопрос:
У меня есть фрейм данных:
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(colnames(results2[q]), 1, 11) <- abs(results2[j, : недопустимая функция при сложном назначении
Какая проблема вызывает это сообщение об ошибке? Как мне это исправить?
Ради репликации все это можно упростить до:
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")
}
Комментарии:
1. Вам действительно стоит прочитать статью «Аккуратные данные» Хэдли Уикхема (google it).
Ответ №1:
Не используйте циклы, а просто векторизируйте. Получите столбцы 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
Комментарии:
1. Есть ли способ сохранить
ID
переменную с помощью этого метода?
Ответ №2:
Краткие замечания по вашему коду для дальнейшего кодирования: Причина ошибки здесь такова: absdiff$substr(colnames(results2[q]),1,11)
поскольку вы не можете использовать знак доллара с функцией только потому, что она возвращает строку, вы можете, однако, использовать разделительные скобки, подобные этой absdiff[substr(colnames(results2[q]),1,11)]
.
Еще одна проблема с кодом заключается в том, что он absdiff
изначально пуст, при вызове results2[FALSE,1:3]
вы получаете имена столбцов, но не строки (если вы хотите удалить все строки FALSE
), что означает, что вы не сможете присвоить значения новому столбцу.
И, наконец, если вы считаете, что вам может понадобиться делать подобные вещи чаще в будущем, я бы рекомендовал вам взглянуть на Аккуратные данные и различные методы, которые вы можете использовать для изменения формы данных, чтобы упростить анализ и сделать его более интуитивным, в качестве примера с вашими выборочными данными вы могли бы сделать что-то вроде этого:
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