【问题标题】:how to apply a function to a certain portion of a filtered data in a data.table in r如何将函数应用于 r 中 data.table 中过滤数据的特定部分
【发布时间】:2020-04-28 21:46:50
【问题描述】:

我有一个 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))

    b.将此部分的小时数列乘以 0.7

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

    一个。 tcode = 230

    b. tcdes = "JKL"

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

    一个。 tcode = 340

    b. 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。

非常感谢。

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    我们可以使用这些值创建一个listdata.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
    

    【讨论】:

    • 非常感谢这个 akrun。我正在更大的 data.table 中实现这一点,完成后将更新此评论。
    • 它工作...非常感谢.. 只是在实际数据表上发出警告:将双 RHS 强制转换为整数以匹配目标列的类型(名为“tcode”的第 11 列)。 RHS 值不包含小数,因此可以更有效地创建为整数。考虑使用 R 的“L”后缀(typeof(0L) 与 typeof(0))将常量创建为整数并避免此警告。用 as.integer() 包裹 RHS 也可以避免这个警告,但如果可能的话,最好首先将 RHS 创建为整数,这样可以避免强制成本。
    • @mraj33 如果是这种情况,您可能需要先将该特定列转换为integerround,因为存在类型匹配
    猜你喜欢
    • 1970-01-01
    • 2020-08-11
    • 1970-01-01
    • 1970-01-01
    • 2012-07-11
    • 2020-05-24
    • 1970-01-01
    • 2019-03-15
    • 1970-01-01
    相关资源
    最近更新 更多