循环,基于现有变量创建新变量,并带条件。

5
我有一些数据,包含400多个列和约80个观测值。我想使用for循环遍历每一列,如果它包含所需的前缀exp_,则我想创建一个新列,该值除以一个参考列,存储为相同名称但带有后缀_pp。我还想使用其他前缀rev_的else if,但我认为只要解决了第一个问题,我就可以自己解决其余问题。以下是一些示例数据:
exp_alpha     exp_bravo    rev_charlie     rev_delta     pupils
10            28           38              95            2
24            56           39              24            5
94            50           95              45            3
15            93           72              83            9
72            66           10              12            3

我第一次尝试时,循环顺利运行,但只存储了if语句为真的最终列,而不是存储每个列中if语句为真的值。我做了一些调整,但失去了那段代码,现在有这个代码,它运行没有错误,但并没有修改数据框。
for (i in colnames(test)) {
  if(grepl("exp_", colnames(test)[i])) {
    test[paste(i,"pp", sep="_")] <- test[i] / test$pupils)
  }
}

我的理解是:

  1. 循环遍历列名的向量
  2. 如果第i个元素中包含子字符串“exp_”,则返回TRUE
  3. 在数据集中创建一个新列,该列是列名向量的第i个元素除以参考类别(学生),并在末尾添加“_pp”
  4. 否则不执行任何操作

我想,由于代码没有报错但是没有执行任何操作,我的问题可能在if()语句中,但我无法找出我的错误。我还尝试在if()语句中添加“== TRUE”,但结果相同。

3个回答

3
几乎正确,你没有定义循环的长度,所以什么也没发生。试一下这个:
for (i in 1:length(colnames(test))) {
  if(grepl("exp_", colnames(test)[i])) {
  test[paste(i,"pp", sep="_")] <- test[i] / test$pupils
  }
}

看起来已经可以了,感谢您的帮助!对于任何使用此代码的人,请注意:当我运行timfaber的建议时,新列名变成了数字,并适当地附加了“_pp”(因为它是第i列,而i是一个数字)。不过修复很简单,在第三行中我替换了 "...paste(i,..." 为 "...paste(colnames(test)[i],..." - cparmstrong

2
作为@timfaber答案的替代方案,您可以保留第一行不变,但不将视为索引:
for (i in colnames(test)) {
  if(grepl("exp_", i)) {
    print(i)
    test[paste(i,"pp", sep="_")] <- test[i] / test$pupils
  }
}

1

线性解决方案:

不要使用循环!您可以将代码线性化并比在列上循环更快地运行它。以下是如何实现:

# Extract column names
cNames <- colnames(test)
# Find exp in column names
foo <- grep("exp", cNames)
# Divide by reference: ALL columns at the SAME time
bar <- test[, foo] / test$pupils
# Rename exp to pp : ALL columns at the SAME time
colnames(bar) <- gsub("exp", "pp", cNames[foo])
# Add to original dataset instead of iteratively appending 
cbind(test, bar)

非常感谢您今天解决了我所有的问题 @PoGibas - cparmstrong

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接