【问题标题】:Create data frame from values in every two continuous rows from an existing data frame从现有数据框中的每两个连续行中的值创建数据框
【发布时间】:2018-03-26 20:57:52
【问题描述】:

我有数据框z1:

z1 <- data.frame(time=as.factor(rep(0.5:9.5,times=rep(c(9,10,8,11,12),2))),
            roi= rep(c(1:9,1:10,1:8,1:11,1:12),2), area=runif(100, 5.0, 7.5))

我想创建一个新的数据框 z2 具有 10*nrow(z1) 行,条件为: 在每个time 值处,i in 1: c(nrow(z1) -1) 的每第二行(z1$roi[i:i+1] and z1$area[i:i+1]) 用于在z2 中创建列roiarea,例如

z2$roi <- seq(z1$roi[i],z1$roi[i+1], length.out = 10)
z2$area <- seq(z1$area[i],z1$area[i+1], length.out = 10)

如果数据框z1 看起来像:

    time roi     area
1    0.5   1 6.181150    #=z1$roi[1]
2    0.5   2 5.469366    #=z1$roi[2]
3    0.5   3 6.742525
.
.
.
98   9.5  10 6.063234
99   9.5  11 6.824393    #=z1$roi[99]
100  9.5  12 7.346298    #=z1$roi[100]

数据框z2 将是:

     time  roi      area
1     0.5 1.000000 6.181150     #=z1$roi[1]
2     0.5 1.111111 6.102063
.
.
.
9     0.5 1.888889 5.548453
10    0.5 2.000000 5.469366     #=z1$roi[2]
.
.
.
991   9.5 11.00000 6.824393     #=z1$roi[99]
992   9.5 11.11111 6.882383
.
.
.
999   9.5 11.88889 7.288309
1000  9.5 12.00000 7.346298     #=z1$roi[100]

谁能帮帮我?谢谢!

【问题讨论】:

  • 您的行号在预期输出中是错误的
  • 听起来像是线性插值问题。例如。 - 参见?approx - 您可以将每行之间的序列值指定为xout= 值。

标签: r dataframe


【解决方案1】:

使用tidyverse,稍微更改您的值以欣赏输出(将5 替换为10):

z1 <- head(z1,3)

library(tidyverse)

z1 %>% 
  mutate_at(vars(roi,area),~map2(.,c(.[-1],last(.)),~seq(.x,.y,length.out=5))) %>%
  unnest %>%
  head(-5)

#    time  roi     area
# 1   0.5 1.00 6.302351
# 2   0.5 1.25 6.151644
# 3   0.5 1.50 6.000938
# 4   0.5 1.75 5.850231
# 5   0.5 2.00 5.699525
# 6   0.5 2.00 5.699525
# 7   0.5 2.25 5.687045
# 8   0.5 2.50 5.674566
# 9   0.5 2.75 5.662087
# 10  0.5 3.00 5.649608
  • 我们将对列timearea 应用相同的转换,因此我们在它们上使用mutate_at

  • 我们想把它们转换成包含向量的列表列,所以我们可以在之后unnest得到一个很长的data.frame(你可能需要熟悉tidyr::unnest才能理解这一步,基本上它使data.frame 中的“常规”data.frame 将具有 vectorslists 或嵌套的 data.frames 作为元素)。

  • map 系列会返回这样一个列表输出,但每个值取决于当前 AND 下一个值,因此我们使用 purrr::map2 来获取两个输入。

  • . 是当前值,c(.[-1],last(.)) 是下一个值(对于最后一个元素没有下一个值,所以我们保留最后一个值)。

  • 我们取消嵌套以创建一个长 data.frames

  • 重复的最后一个值创建了重复的行,所以我们用head(-n)删除它们

【讨论】:

  • @穆迪,万分感谢。那是我所期望的。但我想了解语法,如果你花点时间简单解释一下就好了:) :)
  • @穆迪,这对我来说很有意义:)。非常感谢!
【解决方案2】:

您可以使用approx() 将其作为线性插值问题:

s1 <- seq_len(nrow(z1)-1)
s2 <- rep(s1,each=9)

out <- approx(
  x    = seq_along(z1$area),
  y    = z1$area,
  xout = c(s2 + head(seq(0,1,length.out=10),-1), nrow(z1))
)$y

z1

#  time roi     area
#1  0.5   1 6.413124
#2  0.5   2 6.837422
#3  0.5   3 6.656612

然后使用行索引将结果重新连接在一起:

cbind(z1[c(s2,nrow(z1)),], out)

#    time roi     area      out
#1    0.5   1 6.413124 6.413124
#1.1  0.5   1 6.413124 6.460268
#1.2  0.5   1 6.413124 6.507413
#1.3  0.5   1 6.413124 6.554557
#1.4  0.5   1 6.413124 6.601701
#1.5  0.5   1 6.413124 6.648845
#1.6  0.5   1 6.413124 6.695989
#1.7  0.5   1 6.413124 6.743134
#1.8  0.5   1 6.413124 6.790278
#2    0.5   2 6.837422 6.837422
#2.1  0.5   2 6.837422 6.817332
#2.2  0.5   2 6.837422 6.797242
#2.3  0.5   2 6.837422 6.777152
#2.4  0.5   2 6.837422 6.757062
#2.5  0.5   2 6.837422 6.736972
#2.6  0.5   2 6.837422 6.716882
#2.7  0.5   2 6.837422 6.696792
#2.8  0.5   2 6.837422 6.676702
#3    0.5   3 6.656612 6.656612

这种逻辑应该比为每一行计算一个序列更好地。快速而肮脏的测试大约需要 10 秒,而 100 万行需要 1 分钟。

【讨论】:

  • 感谢您的回答。如果我想对“roi”列进行排序,我会按照你对“area”所做的处理吗?
  • @HoangLe - 大约返回一个“x”值以及“y” - 这应该是部分“roi”值(在这种情况下等于指定的 xout= 参数)
猜你喜欢
  • 1970-01-01
  • 2020-11-13
  • 2023-01-30
  • 2021-10-30
  • 1970-01-01
  • 2020-11-13
  • 2021-09-08
  • 2016-03-19
相关资源
最近更新 更多