首页 > 解决方案 > 如何将函数应用于 r 中 data.table 中过滤数据的特定部分

问题描述

我有一个 data.table 并想做以下事情:

  1. 根据多个条件过滤数据
  2. 将函数应用于单个列上此过滤数据的“部分”
  3. 修改/更新与过滤数据的同一“部分”相对应的其他列
  4. 修改/更新其他列的剩余部分
  5. 所有更新都代替 data.table 完成以保持相同的尺寸

下面是一个例子: 数据表:

dt <- data.table(ename = rep(c('a','b'),10),
                 tcode = rep(c(100,200,300,400),5),
                 tcdes = rep(c('EFG','HIJ','KLM','NGH'),5),
                 hours = rep(c(8),20))
# output
# ename tcode tcdes hours
# 1:     a   100   EFG     8
# 2:     b   200   HIJ     8
# 3:     a   300   KLM     8
# 4:     b   400   NGH     8
# 5:     a   100   EFG     8
# 6:     b   200   HIJ     8
# 7:     a   300   KLM     8
# 8:     b   400   NGH     8
# 9:     a   100   EFG     8
# 10:     b   200   HIJ     8
# 11:     a   300   KLM     8
# 12:     b   400   NGH     8
# 13:     a   100   EFG     8
# 14:     b   200   HIJ     8
# 15:     a   300   KLM     8
# 16:     b   400   NGH     8
# 17:     a   100   EFG     8
# 18:     b   200   HIJ     8
# 19:     a   300   KLM     8
# 20:     b   400   NGH     8

#1. Filter the data by multiple conditions:

dt[(ename == 'b'& tcode == 400),]

# output
#   ename tcode tcdes hours
#1:     b   400   NGH     8
#2:     b   400   NGH     8
#3:     b   400   NGH     8
#4:     b   400   NGH     8
#5:     b   400   NGH     8

  1. 我想应用的功能是:

    一个。取这个过滤数据的某个 %(部分)(比如 70%,这将给出前 3.5 行 - 所以将此值设置为 3 行(行:1 到 3))

    湾。将此部分的小时数列乘以 0.7

  2. 将这部分数据的 tcode 和 tcdes 列修改为:

    一个。时间码 = 230

    湾。tcdes = "JKL"

  3. 将过滤后数据剩余部分(2行:4&5)的tcode和tcdes列修改为:

    一个。时间码 = 340

    湾。tcdes = "BVH"

5. The filtered result should look like:

dt[(ename == 'b'& tcode == 230 & tcode == 340),]

# output
#   ename tcode tcdes hours
#1:     b   230   JKL     5.6
#2:     b   230   JKL     5.6
#3:     b   230   JKL     5.6
#4:     b   340   BVH     8
#5:     b   340   BVH     8

作为一个整体,我是 R 的新手,非常感谢您的帮助。我尝试将 lapply() 与 .SD、.SDcols 和 := 一起使用,:=但无法将该函数应用于某个部分并维护完整的 data.table。

非常感谢。

标签: rdata.table

解决方案


我们可以创建一个listordata.table与值,然后做一个连接或使用Map来替换值

library(data.table)
newdt <- data.table(tcode = c(230, 340), tcdes = c("JKL", "BVH"), hours = c(0.7, 1))
dt[(ename == 'b'& tcode == 400),  names(newdt) := {
         i1 <- as.integer(0.7 * .N)
         i2 <- rep(1:2, c(i1, .N - i1))
          Map(function(x, y, z) if(z) x[i2] * y[i2] else y[i2],
             .SD, newdt, c(FALSE, FALSE, TRUE))
       }, .SDcols = names(newdt)]



dt[(ename == 'b'& tcode == 230 | tcode == 340)]
#   ename tcode tcdes hours
#1:     b   230   JKL   5.6
#2:     b   230   JKL   5.6
#3:     b   230   JKL   5.6
#4:     b   340   BVH   8.0
#5:     b   340   BVH   8.0

推荐阅读