【问题标题】:r - How to create vector with for loops and ifelser - 如何使用 for 循环和 ifelse 创建向量
【发布时间】:2016-08-17 22:03:56
【问题描述】:

我遇到了嵌套 for 循环和 ifelse 语句的问题。这是我的数据框abund

   Species Total C1 C2 C3 C4
1     Blue   223 73 30 70 50
2    Black   221 17 50 56 98
3   Yellow   227 29 99 74 25
4    Green   236 41 97 68 30
5      Red   224 82 55 21 66
6   Orange   284 69 48 73 94
7    Black   154  9 63 20 62
8      Red   171 70 58 13 30
9     Blue   177 57 27  8 85
10  Orange   197 88 61 18 30
11  Orange   112 60  8 31 13

我想将abund 的一些列加在一起,但前提是它们与我在向量colors 中指定的正确物种相匹配。

colors <- c("Black", "Red", "Blue")

因此,如果abund 中的Speciescolor 中的物种相匹配,则将列C2C4 一起添加到一个新向量minus 中。如果abund 中的物种与color 中的物种不匹配,则将0 添加到新向量minus

我的代码有问题,希望这只是定义范围的小问题,但我不确定。到目前为止,这是我的代码:

# Use for loop to create vector of sums for select species or 0 for species not selected
for( i in abund$Species)
{ 
  for( j in colors)
  {
    minus <- ifelse(i == j, sum(abund[abund$Species == i, 
       "C2"]:abund[abund$Species == i, "C4"]), 0)
  }
}

返回这个:There were 12 warnings (use warnings() to see them) 而这个“向量”:minus[1] 0

这是我的目标:

minus
[1] 150 204 0 0 142 0 145 101 120 0 0

感谢您的宝贵时间和帮助。

【问题讨论】:

    标签: r if-statement for-loop


    【解决方案1】:

    如果没有任何循环,这样做可能会更好。

    # Create the vector
    minus <- rep(0, nrow(abund))
    # Identify the "colors" cases
    inColors <- abund[["Species"]] %in% colors
    # Set the values
    minus[inColors] <- rowSums(abund[inColors, c("C2","C3","C4")])
    

    此外,值得一提的是,您的原始代码存在很多问题。首先,您的第一个 for 循环没有按照您的想法进行。在每一轮中,i 的值被设置为abund$Species 中的下一个值,所以首先是Blue,然后是Black,然后是Yellow,等等。结果,然后你使用@987654328 进行索引@,您可以返回多行(例如,Blue 将给您19,因为这两行都是Species == "Blue")。

    第二次,当您编写abund[abund$Species == i, "C2"]:abund[abund$Species == i, "C4"] 语句时,您没有索引列C2 C3C4,您正在创建一个从C2 中的值开始并以C4 中的值结束的序列.例如,当i == "Yellow" 它返回99:25 或99、98、97、...、26、25。您收到这些警告的原因是这个问题和最后一个问题的结合。例如,当i == "Blue" 时,您试图创建一个从 30 和 27 开始并以 50 和 85 结束的序列。警告是说它只是使用开始和结束中的第一个数字并给你@ 987654342@.

    最后,您一直在写minus 的值,而不是添加它。您需要首先像上面一样创建减号并将其编入索引,以便像 minus[i] &lt;- newValue 这样的分配。

    【讨论】:

    • 简洁明了!
    • 你也可以乘以用于inColors - abund$Species %in% colors * rowSums(abund[c("C2","C3","C4")])的逻辑向量
    • 非常感谢@Barker!这就像一个冠军。您的解释很有价值,并消除了我对 for 循环的许多误解。再次感谢。
    【解决方案2】:

    注意ifelse 是矢量化的,因此您通常不需要在使用它时需要任何for 循环。

    我最喜欢 Barker 的回答,但如果您想使用 ifelse 执行此操作,则可以这样做:

    abund$minus = with(abund, ifelse(
        Species %in% colors,  # if the species matches
        C2 + C3 + C4,         # add the columns
        0                     # otherwise 0
    ))
    

    即使这只是一行而 Barker 的为 3,但在大数据上,避免 ifelse 会更有效。

    但是,ifelse 语句可以嵌套,并且在条件变得复杂时通常更容易使用 - 所以肯定有使用它们的好时机。在中小型数据上,速度差异可以忽略不计,因此请使用您首先想到的任何一个。

    【讨论】:

    • 谢谢你,格雷戈尔。我的真实数据集大约有 11088 行,所以我会记住您的建议。
    • 我认为这属于“中型数据”类别。运行两者,看看你是否能注意到不同之处!
    【解决方案3】:
    # Create a column called minus with the length of the number of existing rows. 
    
    # The default value is zero.
    
    abund$minus <- integer(nrow(abund))
    
    # Perform sum of C2 to C4 only in those rows where Species is in the colors vector
    
    abund$minus[abund$Species %in% colors] <- rowSums(abund[abund$Species %in% colors,5:7])
    

    【讨论】:

    • 通过您的编辑,这是 Barker 答案的错误版本 - 几乎相同,但您确实需要在您使用 rowSums 的矩阵中使用条件 abund$Species %in% colors
    • 感谢@Gregor,您的反馈。我相应地编辑了我的答案。我以前的错误版本解释了为什么我收到警告 number of items to replace is not a multiple of replacement length 。我最初的答案是与dplyrtidyr 走上一条非常复杂的道路。我也更喜欢巴克优雅的回答。
    • 但这个答案现在与巴克的答案相同。它增加了什么?
    猜你喜欢
    • 2015-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-18
    • 2019-12-03
    • 1970-01-01
    • 2021-12-08
    • 1970-01-01
    相关资源
    最近更新 更多