首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使用[r] data.table (如果可能的话)对前面的行执行多行依赖关系的逐行操作

如何使用[r] data.table (如果可能的话)对前面的行执行多行依赖关系的逐行操作
EN

Stack Overflow用户
提问于 2019-06-13 17:59:22
回答 3查看 183关注 0票数 5

我有以下数据表:

代码语言:javascript
运行
复制
dt <- fread("
  ID   | EO_1 | EO_2 | EO_3 | GROUP
ID_001 | 0.5  |  1.2 |      |   A  
ID_002 |      |      |      |   A
ID_003 |      |      |      |   A
ID_004 |      |      |      |   A
ID_001 | 0.4  |  2.5 |      |   B
ID_002 |      |      |      |   B
ID_003 |      |      |      |   B
ID_004 |      |      |      |   B  
            ", 
            sep = "|",
            colClasses = c("character", "numeric", "numeric", "numeric", "character"))

我正在尝试执行一些逐行操作,这些操作有时依赖于前几行的数据。更具体而言:

代码语言:javascript
运行
复制
calc_EO_1 <- function(
  EO_1,
  EO_2
){
  EO_1 <- shift(EO_1, type = "lag") * shift(EO_2, type = "lag")
  return(EO_1)
}

calc_EO_2 <- function(
  EO_1,
  EO_2,
  EO_3
){
  EO_2 <- EO_1 * shift(EO_2, type = "lag") * shift(EO_3, type = "lag")
  return(EO_2)
}

calc_EO_3 <- function(
  EO_1,
  EO_2
){
  EO_3 <- EO_1 * EO_2
  return(EO_3)
}

最后一个操作将需要从第一行中计算,因为它依赖于其他字段(这应该很容易),在此之后,所有三个操作都必须以连续和逐行的方式进行。

我最近的一次经历是:

代码语言:javascript
运行
复制
first_row_bygroup_index <- dt[, .I[1], by = GROUP]$V1

dt[first_row_bygroup_index, 
   EO_3 := calc_EO_3(EO_1, EO_2)
     ]

dt[!first_row_bygroup_index, 
   `:=` (
     EO_1 = calc_EO_1(EO_1, EO_2),
     EO_2 = calc_EO_2(EO_1, EO_2, EO_3),
     EO_3 = calc_EO_3(EO_1, EO_2)
     ),
   by = row.names(dt[!first_row_bygroup_index])]

但它只正确地计算第一行:

代码语言:javascript
运行
复制
  ID   | EO_1 | EO_2 | EO_3 | GROUP
ID_001 | 0.5  |  1.2 |  0.6 |   A  
ID_002 |      |      |      |   A
ID_003 |      |      |      |   A
ID_004 |      |      |      |   A
ID_001 | 0.4  |  2.5 |  1.0 |   B
ID_002 |      |      |      |   B
ID_003 |      |      |      |   B
ID_004 |      |      |      |   B  

就是那些空间。

我不认为我离解决方案太远,但我无法找到办法使它发挥作用。问题是,我不能使用子集外的行在子集中执行操作。

编辑我错过了预期的结果:

代码语言:javascript
运行
复制
  ID   |   EO_1      |     EO_2      |       EO_3      | GROUP
ID_001 |  0.50000000 |   1.20000000  |      0.60000000 |   A  
ID_002 |  0.60000000 |   0.43200000  |      0.25920000 |   A
ID_003 |  0.25920000 |   0.02902376  |      0.00752296 |   A
ID_004 |  0.00752296 |   0.00000164  |      0.00000001 |   A
ID_001 |  0.40000000 |   2.50000000  |      1.00000000 |   B
ID_002 |  1.00000000 |   2.50000000  |      2.50000000 |   B
ID_003 |  2.50000000 |  15.62500000  |     39.06250000 |   B
ID_004 | 39.06250000 | 23841.8580000 | 931322.57810000 |   B   

新编辑--我想出了以下代码片段,但我宁愿稍等片刻,看看是否有人能得到比这个更有效的解决方案:

代码语言:javascript
运行
复制
while(any(is.na(dt))){
  dt[, `:=` (
    EO_3 = calc_EO_3(EO_1, EO_2),
    EO_1 = ifelse(ID == "ID_001", EO_1, calc_EO_1(EO_1, EO_2)),
    EO_2 = ifelse(ID == "ID_001", EO_2, calc_EO_2(EO_1, EO_2, EO_3))
  )]  
}

我已经想出了一个类似的dplyr解决方案,并且还提供了一个丑陋的期间循环修复。关键是找到一种方法来进行行级计算,该计算可以从前面的行中获取信息,即使该行之前的行将超出所选子集的范围。我希望有人能改进这一点,所以我会等一会儿才把它标记为解决方案。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-06-17 01:58:05

以下是另一种可能的办法:

代码语言:javascript
运行
复制
dt[!is.na(EO_1), EO_3 := EO_1 * EO_2, by=.(GROUP)]
dt[ID!="ID_001", c("EO_1", "EO_2", "EO_3") :=
    dt[,
        {
            eo1 <- EO_1[1L]; eo2 <- EO_2[1L]; eo3 <- EO_3[1L]
            .SD[ID!="ID_001",
                {
                    eo1 <- eo1 * eo2
                    eo2 <- eo1 * eo2 * eo3
                    eo3 <- eo1 * eo2
                    .(eo1, eo2, eo3)
                },
                by=.(ID)]
        },
        by=.(GROUP)][, -1L:-2L]
]

产出:

代码语言:javascript
运行
复制
       ID        EO_1         EO_2         EO_3 GROUP
1: ID_001  0.50000000 1.200000e+00 6.000000e-01     A
2: ID_002  0.60000000 4.320000e-01 2.592000e-01     A
3: ID_003  0.25920000 2.902376e-02 7.522960e-03     A
4: ID_004  0.00752296 1.642598e-06 1.235720e-08     A
5: ID_001  0.40000000 2.500000e+00 1.000000e+00     B
6: ID_002  1.00000000 2.500000e+00 2.500000e+00     B
7: ID_003  2.50000000 1.562500e+01 3.906250e+01     B
8: ID_004 39.06250000 2.384186e+04 9.313226e+05     B
票数 2
EN

Stack Overflow用户

发布于 2019-06-14 19:56:22

这是您希望最终产品看起来像的那种数据吗?

代码语言:javascript
运行
复制
go <- function(x, y, n) {
  z <- x * y
  for (i in 1:(n - 1)) {
    x <- c(x[1] * y[1], x)
    y <- c(x[1] * y[1] * z[1], y)
    z <- x * y
  }
  data.table(EO_1 = x, EO_2 = y, EO_3 = z)[.N:1][, lapply(.SD, round, 8)]
}

go(.5, 1.2, 4)

         EO_1       EO_2       EO_3
1: 0.50000000 1.20000000 0.60000000
2: 0.60000000 0.43200000 0.25920000
3: 0.25920000 0.02902376 0.00752296
4: 0.00752296 0.00000164 0.00000001
票数 1
EN

Stack Overflow用户

发布于 2019-06-17 07:28:49

棘手的问题!我试着使用dplyr的nest并应用了一个costum函数。

代码语言:javascript
运行
复制
options("scipen"=999, "digits"=8)
library(tidyverse)

# Custom function
logic <- function(.df){
  for(i in 2:nrow(.df)){
    .df[i, "EO_1"] <- .df[i-1, "EO_1"] * .df[i-1, "EO_2"]
    .df[i, "EO_2"] <- .df[i, "EO_1"] * .df[i-1, "EO_2"] * .df[i-1, "EO_3"]
    .df[i, "EO_3"] <- .df[i, "EO_1"] * .df[i, "EO_2"]
  }
  .df
}

# Answers the question
dt <- dt %>% 
  mutate(EO_3 = EO_1 * EO_2) %>% 
  nest(-GROUP) %>% 
  mutate(data = map(data, ~logic(.))) %>% 
  unnest()

# Fixing nice output
dt %>% 
  mutate_at(vars(contains("EO_")), ~round(., 8)) %>% 
  select(-GROUP, everything(), GROUP) %>% 
  as.data.frame()

给你

代码语言:javascript
运行
复制
      ID        EO_1           EO_2            EO_3 GROUP
1 ID_001  0.50000000     1.20000000      0.60000000     A
2 ID_002  0.60000000     0.43200000      0.25920000     A
3 ID_003  0.25920000     0.02902376      0.00752296     A
4 ID_004  0.00752296     0.00000164      0.00000001     A
5 ID_001  0.40000000     2.50000000      1.00000000     B
6 ID_002  1.00000000     2.50000000      2.50000000     B
7 ID_003  2.50000000    15.62500000     39.06250000     B
8 ID_004 39.06250000 23841.85791016 931322.57461548     B
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56586162

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档