r - R data.table 在某些条件下从现有列基础计算新列
问题描述
假设我有以下数据表:
dta <- data.table(
criteria = c('A', 'A', 'B', 'A', 'A', 'B'),
phase = list('block3', c('block1', 'block2'), 'block2', 'block2', 'block3', 'block1'),
start_val = c(12.0, 1.0, 7.0, 7.0, 12.0, 1.0),
end_val = c(15.0, 11.0, 11.0, 11.0, 15.0, 6.0),
max_val = c(13.0, 8.0, 9.5, 11.0, 15.0, 6.0)
)
我需要从中得到带有两个附加列的结果表,cor_start
并且cor_end
dtb <- data.table(
criteria = c('A', 'A', 'B', 'A', 'A', 'B'),
phase = list('block3', c('block1', 'block2'), 'block2', 'block2', 'block3', 'block1'),
start_val = c(12.0, 1.0, 7.0, 7.0, 12.0, 1.0),
end_val = c(15.0, 11.0, 11.0, 11.0, 15.0, 6.0),
max_val = c(13.0, 8.0, 9.5, 11.0, 15.0, 6.0),
cor_start = c(12.0, 1.0, 8.0, 9.5, 13.0, 6.0),
cor_end = c(13.0, 8.0, 9.5, 11.0, 15.0, 6.0)
)
phases
新列需要通过检查是否有任何前一行与当前匹配的阶段值来参考列来计算。
为了更好地理解,在这个例子中:
- 第 3 行在第 2 行中具有 block2 的匹配阶段
- 第 4 行在第 3 行中具有 block2 的匹配阶段
- 第 5 行在第 1 行中具有 block3 的匹配阶段
- 第 6 行在第 2 行中具有 block1 的匹配阶段
但是第 1 行和第 2 行没有先前匹配的阶段行。请注意,phase
是类型列表。
因此,当有前一个匹配行时,条件如下:
if (max_val in previous matching row is < end_val in current row)
cor_start = previous matching row max_val
cor_end = current row end_val
if (max_val in previous matching row is > end_val in current row)
cor_start = current row end_val
cor_end = current row end_val
并且当没有先前的匹配行时,以下是条件:
cor_start = current row start_val
cor_end = current row max_val
我查看了 shift(),但不知道如何设置上述条件?谢谢!
解决方案
就像是:
dta_transformed <- dta[,.(rn = .I, phase = unlist(phase)), by = setdiff(names(dta), 'phase')][
, shifted_max := shift(max_val), by = phase][
shifted_max < end_val, `:=` (cor_start = shifted_max, cor_end = end_val), by = phase][
shifted_max > end_val, `:=` (cor_start = end_val, cor_end = end_val), by = phase][
is.na(cor_start), `:=` (cor_start = start_val, cor_end = max_val), by = phase][
, phase := paste(phase, collapse = ","), by = rn][!duplicated(rn),][
, c("rn", "shifted_max") := NULL]
但是,我得到的输出是:
criteria phase start_val end_val max_val cor_start cor_end
1: A block3 12 15 13.0 12.0 13
2: A block1,block2 1 11 8.0 1.0 8
3: B block2 7 11 9.5 8.0 11
4: A block2 7 11 11.0 9.5 11
5: A block3 12 15 15.0 13.0 15
6: B block1 1 6 6.0 6.0 6
是不是在第 3 行cor_end
中,您想要的输出中应该是 11?由于前一个匹配的行 (2) 具有较低的 ,因此应该采用max_val
当前的(11) 吗?end_val
还有这种tidyverse
方法,更具可读性:
library(tidyverse)
dta %>% mutate(rn = row_number()) %>%
unnest(phase) %>%
group_by(phase) %>%
mutate(
cor_start = case_when(
lag(max_val) < end_val ~ lag(max_val),
lag(max_val) > end_val ~ end_val,
TRUE ~ start_val
),
cor_end = if_else(!is.na(lag(max_val)), end_val, max_val)
) %>% group_by(rn) %>%
mutate(
phase = paste(phase, collapse = ",")
) %>% ungroup() %>% select(-rn) %>% distinct()
推荐阅读
- django - 从 django 中的查询集的所有对象中获取数据
- javascript - 无论如何在第一个函数中用异步重写这个函数。而不是“新的承诺”?
- r - 如何对也符合 R 中另一个标准的分类变量进行分组?DPLYR?
- ag-grid - Ag-grid(社区版)分页文字自定义
- python - PyQt5 带有链接的标签格式不正确
- c++ - 为什么标准范围算法为右值参数返回 std::ranges::dangling 而不是......好吧,只是工作?
- ruby-on-rails - 为什么简单表单在 Rails 中不显示验证错误消息?
- android - 为 Android 中的 WebView 内的按钮设置 onClick 侦听器
- javascript - 如何让一个函数在运行之前等待另一个函数的完成
- css - Bootstrap 类留下了一些我需要删除的空格