2016-08-17 32 views
0

我遇到嵌套for循环和ifelse语句的问题。这是我的数据框abundr - 如何用for循环和ifelse创建矢量

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") 

所以,如果在abundSpeciescolor物种匹配,则通过C4添加列C2起来的一种新型载体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 

谢谢您的时间,帮助这一点。

回答

3

这可能会更好地完成没有任何循环。

# 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,等。结果,则使用索引abund[abund$Species == i, ],则可能返回多行(例如:Blue将给你19,因为这两行都是Species == "Blue")。

其次,当你让abund[abund$Species == i, "C2"]:abund[abund$Species == i, "C4"]你是不是索引列C2C3及本声明C4你正在在C2开始值和C4在值结束的序列。例如,当i == "Yellow"它返回99:25或99,98,97,...,26,25。你得到这些警告的原因是这个问题和最后一个问题的组合。例如,当您试图从30和27开始到50和85结束时,您正在尝试创建一个序列。该警告说,它只是在开始和结束时使用第一个数字,然后给您30:50

最后,你总是写下你的价值minus而不是增加它。您需要首先创建减号,并将其编入索引,如minus[i] <- newValue

+0

好又直爽! – Gregor

+1

你也可以乘以用于'inColors'的逻辑向量 - '%abund * Species%in%colors * rowSums(abund [c(“C2”,“C3”,“C4”)])' – thelatemail

+0

非常感谢很多,@巴克!这就像一个冠军。你的解释值得很多,并澄清了我对循环的许多误解。再次感谢。 – Metridia

-1
# 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]) 
+0

随着你的编辑,这是一个巴克版本的答案 - 几乎相同,但你确实需要在你使用'rowSums'的矩阵中使用'%colors'种类%的条件。 – Gregor

+0

感谢@Gregor,感谢您的反馈。我相应地编辑了我的答案。我以前的buggy版本解释了为什么我得到警告“要替换的项目数不是替换长度的倍数”。我原来的回答是用'dplyr'和'tidyr'走了一条非常复杂的路。我也很喜欢巴克的优雅答案。 – ropolo

+0

但是这个答案现在与Barker的答案相同。它增加了什么? – Gregor

2

注意ifelse被矢量因此你通常使用时需要任何for循环。

我喜欢巴克的回答最好,但如果你想做到这一点与ifelse这是这样的:

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

即使这只是一个线和巴克的是3,大数据也将略有更高效地避免ifelse

但是,ifelse语句可以嵌套,并且在条件变得复杂时通常更容易使用 - 所以使用它们绝对是好时机。在中小尺寸数据上,速度差异可以忽略不计,因此只要您首先考虑使用即可。

+0

谢谢你,格雷戈尔。我的真实数据集大约有11088行,所以我会记住你的建议。 – Metridia

+0

我会认真考虑“中等数据”类别。运行两个,看看你是否能注意到一个区别! – Gregor