【问题标题】:Expand data.frame rows by criteria按条件展开 data.frame 行
【发布时间】:2014-06-05 15:13:54
【问题描述】:

我想知道是否可以使用 dplyr 根据每行中的条件扩展 data.frame 的行。如果在 dplyr 中不可能,我很乐意提供任何解决方案!

这是我的数据示例

data.frame(plot=rep(c(6,7),each=4),
           trans=rep(c("0,0","0,100","100,100","100,0"),2),
           length_m=c(350,200,200,50,45,200,125,75)        )

plot   trans length_m
6     0,0      350
6   0,100      200
6 100,100      200
6   100,0       50
7     0,0       45
7   0,100      200
7 100,100      125
7   100,0       75

上面的数据代表两个图。一般来说,我的每个地块都有 1 到 4 个横断面,用 0,0 标识; 0,100; 100,100;或 100,0(上面的图都有所有四个可能的样带)。每个样带的长度由 length_m 给出。我想做的是将每个样带除以长度 L,并为每个新样带做一行。如果最后的样带

因此,如果 L = 100,上述数据集将如下所示

plot    trans length_m
6       0,0_0      100
6     0,0_100      100
6     0,0_200      150
6     0,100_0      100
6   0,100_100      100
6   100,100_0      100
6 100,100_100      100
6     100,0_0       50
7       0,0_0       45
7     0_100_0      100
7   0,100_100      100
7   100,100_0      125
7     100,0_0       75

请注意,350 米长的 6, 0,0 分为 0,100 和 200 部分,长度分别为 100,100 和 150,而 50 米长的 6, 100,0 只是一个单独的部分 0,并且是仍然有 50 米长。

我已经尝试了几种不同的方法来完成这项工作,但没有什么值得发布的,所以任何帮助都将不胜感激!

【问题讨论】:

  • 这并不难实现。您只需按plottrans 进行分组。但作为 data.table 用户,我将继续回答 dplyr 粉丝,因为您似乎更喜欢这样。
  • 转换后sum(length)应该一样吗?即“0,0_300”行的长度是否应该为50,因为“0,0”之前的长度是350,但现在是450?不是所有的长度都应该小于L吗?
  • 嗨 MrFlick - 很棒的收获!抱歉,我搞砸了所需的输出。是的,你是正确的 sum(length) 在转换后应该是相同的。我已经修复了输出,希望这更有意义。所有长度可能不小于 L。这是因为如果样带的末端有一个小于 L 的残差,则应将其添加到前一个样带。这就是为什么 350 m 样带被分成长度为 100,100,150 的部分。希望对您有所帮助!

标签: r dplyr


【解决方案1】:

这是一个数据表解决方案,假设您的原始数据在数据框中df

df$trans <- as.character(df$trans)   # need trans to be char, not factor
library(data.table)
dt <- data.table(df)         
L <- 100
f <- function(x) {                   # implements the partitioning
  if (x<L) return(x)
  y <- rep(L,as.integer(x/L))
  y[length(y)] <- y[length(y)]+x-sum(y)
  return(y)
}
result <- dt[,list(length_m=f(length_m)),by=list(plot,trans)]
result[,trans:=paste(trans,L*(0:(.N-1)),sep="_"),by=list(plot,trans)]
result
#     plot       trans length_m
#  1:    6       0,0_0      100
#  2:    6     0,0_100      100
#  3:    6     0,0_200      150
#  4:    6     0,100_0      100
#  5:    6   0,100_100      100
#  6:    6   100,100_0      100
#  7:    6 100,100_100      100
#  8:    6     100,0_0       50
#  9:    7       0,0_0       45
# 10:    7     0,100_0      100
# 11:    7   0,100_100      100
# 12:    7   100,100_0      125
# 13:    7     100,0_0       75

【讨论】:

    【解决方案2】:

    这是一个 dplyr 解决方案 - 虽然不是很优雅。

    df <- data.frame(plot=rep(c(6,7),each=4),
               trans=rep(c("0,0","0,100","100,100","100,0"),2),
               length_m=c(350,200,200,50,45,200,125,75)        )
    
    df %>% 
      mutate(rnum = row_number(),
             freq = pmax(floor(length_m/100),1)) %>%
      group_by(rnum) %>% complete(
        freq = 1:freq
      ) %>% mutate_all(
        funs(last(.))
      ) %>% mutate(
        within.rnum = row_number(),
        trans = paste0(trans,"_",100*(within.rnum-1)),
        length_m = ifelse(within.rnum==n(),(length_m - 100*(floor(length_m/100))) + 100*(length_m>100),100)
      ) %>% ungroup %>% select(-rnum,-within.rnum,-freq)
    
    # Source: local data frame [13 x 4]
    # Groups: rnum [6]
    # 
    # rnum  freq         x         y
    # <int> <dbl>     <dbl>     <dbl>
    #   1      1     1 0.8894632 1.4368569
    # 2      2     1 0.4325821 0.9366039
    # 3      3     2 0.2039089 0.6234862
    # 4      3     2 0.2039089 0.6234862
    # 5      4     2 0.9493441 1.5977998
    # 6      4     2 0.9493441 1.5977998
    # 7      5     3 0.9806209 1.7840731
    # 8      5     3 0.9806209 1.7840731
    # 9      5     3 0.9806209 1.7840731
    # 10     6     4 0.8778605 1.4682580
    # 11     6     4 0.8778605 1.4682580
    # 12     6     4 0.8778605 1.4682580
    # 13     6     4 0.8778605 1.4682580
    

    对于 dplyr 中的“扩展”数据集,我发现以下 group_by row_number() 然后应用 complete() 结构来工作,例如:

    df <- data_frame(x=runif(n=6),y=x+runif(n=6),freq=c(1,1,2,2,3,4))
    
    df %>% mutate(rnum = row_number()) %>%
      group_by(rnum) %>% complete(
        freq = 1:freq
      ) %>% mutate_all(
        funs(last(.))
      )
    
    # Source: local data frame [13 x 4]
    # Groups: rnum [6]
    # 
    # rnum  freq         x         y
    # <int> <dbl>     <dbl>     <dbl>
    #   1      1     1 0.8894632 1.4368569
    # 2      2     1 0.4325821 0.9366039
    # 3      3     2 0.2039089 0.6234862
    # 4      3     2 0.2039089 0.6234862
    # 5      4     2 0.9493441 1.5977998
    # 6      4     2 0.9493441 1.5977998
    # 7      5     3 0.9806209 1.7840731
    # 8      5     3 0.9806209 1.7840731
    # 9      5     3 0.9806209 1.7840731
    # 10     6     4 0.8778605 1.4682580
    # 11     6     4 0.8778605 1.4682580
    # 12     6     4 0.8778605 1.4682580
    # 13     6     4 0.8778605 1.4682580
    

    虽然我认为使用 base R 有一些简单的方法可以做到这一点(例如,Replicate each row of data.frame and specify the number of replications for each row 的答案)。

    【讨论】:

      猜你喜欢
      • 2022-01-10
      • 1970-01-01
      • 2018-11-30
      • 1970-01-01
      相关资源
      最近更新 更多