按条件展开data.frame行

时间:2014-06-05 15:13:55

标签: r dplyr

我想知道是否可以使用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,然后应将该距离添加到上一个横断面。

因此,如果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和0,100。 200,长度100,100& 150,而长度为50米的6,100,0只是一个0区,仍然是50米长。

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

2 个答案:

答案 0 :(得分:2)

这是一个数据表解决方案,假设您的原始数据位于数据框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

答案 1 :(得分:0)

这是一个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

虽然我认为有很简单的方法可以使用基数R(例如Replicate each row of data.frame and specify the number of replications for each row的答案)。