双循环填充数据框-如何修复“复杂分配中的无效功能”

时间:2019-04-11 09:00:39

标签: r loops dataframe for-loop

我有一个数据框:

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
.       .                 .                      .                .
.       .                 .                      .                .

2016年有140个问题,2017年有140个问题,每年这些问题使用相同的名称,但是每个变量名的末尾都有"_2016""_2017"以区分时间段。

>

和另一个数据框:

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

我想通过对每个ID的每个问题求出两年的绝对差值来以absdiff分配一个值。

在我的情况下,我在结果2中检查了2016年的问题编号(或变量名的前几个字符)是否匹配2017年的问题编号。

如果成立,我想将两个答案的绝对差分配给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")
}

2 个答案:

答案 0 :(得分:5)

不使用循环,而只是向量化。获取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 :(得分:2)

关于您的代码的快速注释,以备将来使用:这里的错误原因是:absdiff$substr(colnames(results2[q]),1,11),因为您不能仅通过函数返回字符串来使用美元符号,但是可以使用像这样absdiff[substr(colnames(results2[q]),1,11)]切成括号。

该代码的另一个问题是,当调用absdiffresults2[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