避免循环,根据id列调整列

时间:2018-04-18 21:06:17

标签: r loops dataframe apply

我的目标是使用它们的高度确定图(id)中成功树的数量。成功的树木是其最大邻居(neighbor_ht)高度的85%的树木。在每个地块中,所有树木都观察到它们的物种(物种)和从它们的直径估算的高度(est_height)但是总有一棵树在那里直接观察高度(dom_species,dom_ht)。

#Create Example data set

id<-c(rep(1,3),rep(2,7))
species<- 
c("oak","maple","oak","maple","maple","apple","oak","maple","maple","maple")
est_ht<-c(11,24.5,32.3,6.5,7.8,23.4,23.4,32.3,33.5,33.5)
dom_species<-c(rep("oak",3),rep("maple",7))
dom_ht<-c(rep(32,3),rep(45,7))
neighbor_ht<-c(rep(34,3),rep(46,7))

df<-data.frame(id,species,est_ht,dom_species,dom_ht,neighbor_ht)

#calculate success

df$success<-ifelse(est_ht>=(0.85*neighbor_ht),1,0)
df

    id species  est_ht  dom_species dom_ht   neighbor_ht success
1   1     oak   11.0         oak     32          34       0
2   1   maple   24.5         oak     32          34       0
3   1     oak   32.3         oak     32          34       1
4   2   maple    6.5       maple     45          46       0
5   2   maple    7.8       maple     45          46       0
6   2   apple   23.4       maple     45          46       0
7   2     oak   23.4       maple     45          46       0
8   2   maple   32.3       maple     45          46       0
9   2   maple   33.5       maple     45          46       0
10  2   maple   33.5       maple     45          46       0

在图2中,应该有1个枫树成功,但估计的高度太低。我想在连续的情节中添加1个成功,其中&#34;物种&#34;匹配&#34; dom_species&#34;当观察到&#34; dom_ht&#34;高于&#34; est_ht&#34;但这只应该为最高的&#34; est_ht&#34;在领带的情况下只有一次。结果数据框应该如下所示。请注意,已成功添加到id = 2中的其中一个枫树的最后一行,&#34; success_2&#34; = 1

df$success_2<-c(0,0,1,0,0,0,0,0,0,1)
df

 id species est_ht dom_species dom_ht neighbor_ht success success_2
1     oak   11.0         oak     32          34       0         0
1   maple   24.5         oak     32          34       0         0
1     oak   32.3         oak     32          34       1         1
2   maple    6.5       maple     45          46       0         0
2   maple    7.8       maple     45          46       0         0
2   apple   23.4       maple     45          46       0         0
2     oak   23.4       maple     45          46       0         0
2   maple   32.3       maple     45          46       0         0
2   maple   33.5       maple     45          46       0         0
2   maple   33.5       maple     45          46       0         1

我在多次for循环尝试时失败了,还有一些使用了apply函数。我没有把它们贴在这里以保持简单。我觉得这个问题有一个优雅的解决方案,不需要使用for循环。

1 个答案:

答案 0 :(得分:0)

以下内容将再现您的预期输出。应该有更优雅的方法来达到同样的效果,考虑到你的问题陈述,这看起来非常复杂。

library(tidyverse);
df %>%
    mutate_if(is.factor, as.character) %>%
    group_by(dom_species) %>%
    arrange(dom_ht) %>%
    mutate(
        success = ifelse(est_ht >= 0.85 * neighbor_ht, 1, 0),
        success_2 = case_when(
            est_ht >= 0.85 * neighbor_ht ~ 1,
            species == dom_species & dom_ht > est_ht & est_ht == max(est_ht) ~ 1,
            TRUE ~ 0),
        success_2 = success_2 - lead(success_2, default = 0),
        success_2 = ifelse(success_2 < 0, 0, success_2))
## A tibble: 10 x 9
## Groups:   dom_species [2]
#      id species est_ht dom_species dom_ht neighbor_ht   success success_2
#   <dbl> <chr>    <dbl> <chr>        <dbl>       <dbl>     <dbl>     <dbl>
# 1    1. oak      11.0  oak            32.         34.        0.        0.
# 2    1. maple    24.5  oak            32.         34.        0.        0.
# 3    1. oak      32.3  oak            32.         34.        1.        1.
# 4    2. maple     6.50 maple          45.         46.        0.        0.
# 5    2. maple     7.80 maple          45.         46.        0.        0.
# 6    2. apple    23.4  maple          45.         46.        0.        0.
# 7    2. oak      23.4  maple          45.         46.        0.        0.
# 8    2. maple    32.3  maple          45.         46.        0.        0.
# 9    2. maple    33.5  maple          45.         46.        0.        1.
#10    2. maple    33.5  maple          45.         46.        0.        0.

说明:ifelsecase_when部分实现了帖子中列出的逻辑规则。我们使用lead来处理est_ht == max(est_ht)中的“关系”,并仅保留最后一个条目。