如何在R data.table中逐行使用ifelse?

时间:2018-10-13 20:37:08

标签: r data.table

我想在<template> <div id="app"> <div> <router-link to="/search">Search</router-link> :: <router-link to="/about">About</router-link> <router-link to="/">Home</router-link> :: <router-link to="/api/places">Place API</router-link> :: </div> <router-view></router-view> </div> </template> R中创建一个新列,该列基于不同列的data.table比较。但是,我希望将ifelse()语句逐行应用。我尝试使用ifelse的组by功能,但似乎按行应用data.table的{​​{1}}条件,但评估test条件跨列中的所有值,而不是使用ifelse条件按行进行操作。下面是一个示例以及我尝试过的一些解决方案。

我有这样的yes by

R

我想要以下输出:

data.table

我尝试过的解决方案:

尝试#1),没有错误,但是在> set.seed(45) > DT <- data.table(date = c(rep("2018-01-01", 3), rep("2018-01-02", 3), rep("2018-01-03", 3)), + id = rep(letters[1:3], 3), + v1 = sample(x = -20:20, size = 9), + v2 = sample(x = -20:20, size = 9)) > str(DT) Classes ‘data.table’ and 'data.frame': 9 obs. of 4 variables: $ date: chr "2018-01-01" "2018-01-01" "2018-01-01" "2018-01-02" ... $ id : chr "a" "b" "c" "a" ... $ v1 : int 5 -8 -11 -6 -7 -10 -13 -2 -14 $ v2 : int -20 -6 14 -9 -3 -5 19 12 -16 - attr(*, ".internal.selfref")=<externalptr> > DT date id v1 v2 1: 2018-01-01 a 5 -20 2: 2018-01-01 b -8 -6 3: 2018-01-01 c -11 14 4: 2018-01-02 a -6 -9 5: 2018-01-02 b -7 -3 6: 2018-01-02 c -10 -5 7: 2018-01-03 a -13 19 8: 2018-01-03 b -2 12 9: 2018-01-03 c -14 -16 > DT_out date id v1 v2 c 1: 2018-01-01 a 5 -20 0 2: 2018-01-01 b -8 -6 0 3: 2018-01-01 c -11 14 11 4: 2018-01-02 a -6 -9 0 5: 2018-01-02 b -7 -3 0 6: 2018-01-02 c -10 -5 0 7: 2018-01-03 a -13 19 13 8: 2018-01-03 b -2 12 2 9: 2018-01-03 c -14 -16 0 中所有值上评估min。这种行为是可以预期的。但是,对我来说奇怪的是,即使没有设置v1或没有声明v2,它也会按行评估test条件:

key

尝试#2):当我设置by并使用> DT[, c := ifelse(v1 < 0 & v2 > 0, min(-v1, v2), 0)] > DT date id v1 v2 c 1: 2018-01-01 a 5 -20 0 2: 2018-01-01 b -8 -6 0 3: 2018-01-01 c -11 14 -20 4: 2018-01-02 a -6 -9 0 5: 2018-01-02 b -7 -3 0 6: 2018-01-02 c -10 -5 0 7: 2018-01-03 a -13 19 -20 8: 2018-01-03 b -2 12 -20 9: 2018-01-03 c -14 -16 0 条件时,什么都没有改变,但是我收到一条错误消息。

key

由于by> setkey(DT, date, id) > DT[, c := ifelse(v1 < 0 & v2 > 0, min(-v1, v2), 0), by = list(date, id)] Error in `[.data.table`(DT, , `:=`(c, ifelse(v1 < 0 & v2 > 0, min(-v1, : Type of RHS ('integer') must match LHS ('double'). To check and coerce would impact performance too much for the fastest cases. Either change the type of the target column, or coerce the RHS of := yourself (e.g. by using 1L instead of 1) > DT date id v1 v2 c 1: 2018-01-01 a 5 -20 0 2: 2018-01-01 b -8 -6 0 3: 2018-01-01 c -11 14 -20 4: 2018-01-02 a -6 -9 0 5: 2018-01-02 b -7 -3 0 6: 2018-01-02 c -10 -5 0 7: 2018-01-03 a -13 19 -20 8: 2018-01-03 b -2 12 -20 9: 2018-01-03 c -14 -16 0 的组合对于每一行都是唯一的,所以我更难理解为什么没有为每个date对此进行评估,这是,在这种情况下,每一行。

也许我需要在id中使用group.SDcols = .(date, id),但是我不知道如何在.SD中使用ifelse

1 个答案:

答案 0 :(得分:6)

您需要使用pmin而不是min

DT[, c := ifelse(v1 < 0 & v2 > 0, pmin(-v1, v2), 0)]

> DT
         date id  v1  v2  c
1: 2018-01-01  a   5 -20  0
2: 2018-01-01  b  -8  -6  0
3: 2018-01-01  c -11  14 11
4: 2018-01-02  a  -6  -9  0
5: 2018-01-02  b  -7  -3  0
6: 2018-01-02  c -10  -5  0
7: 2018-01-03  a -13  19 13
8: 2018-01-03  b  -2  12  2
9: 2018-01-03  c -14 -16  0

# see also:
?pmin
  

pmax *()和pmin *()将一个或多个向量作为参数,将它们循环使用相同的长度,并返回单个向量,并赋予“ parallel”   参数向量的最大值(或最小值)。

[稍后添加]

如果您首先更改列类型,您的原始代码也可以正常工作

  DT[, v1:= as.numeric(v1)]   # was integer, converting to 'double'
  DT[, v2:= as.numeric(v2)]   # ---,,---
  DT[, c := ifelse(v1 < 0 & v2 > 0, min(-v1, v2), 0), by = list(date, id)]

据我所知,data.table的原则不是让R隐式更改列类型,而是使类型保持不变,直到显式更改为止。

手册说:

  

不同于<-对于data.frame,(可能较大的)LHS不会被强制匹配(通常   小)RHS。相反,如有必要,RHS被强制匹配LHS的类型。在哪里   涉及将双精度值强制转换为整数列,并给出警告(是否   分数数据是否被截断)。这样做的动机是效率。最好得到专栏   类型可以预先纠正并坚持下去。更改列类型是可能的,但是故意要困难一些:   提供整个专栏作为RHS。然后将此RHS插入该列插槽,我们称之为   plonk语法,或者根据需要替换列语法。通过构造一个全长向量   一种新的类型,您作为用户可以更清楚地了解发生了什么,并且读者可以更清楚地了解   您确实打算更改列类型的代码。

到目前为止,一切都很好。但是,当然,原始错误消息令人困惑。

 # To check and coerce would impact performance too much for the fastest cases. 

“用于最快的情况?”。这必须是最快的情况之一,因为数据集在微观上很小,而且我敢打赌,如果data.table允许隐式类型转换,那么在这种情况下,没有人会注意到性能的影响。因此,产生此错误消息的主要动机似乎是程序包作者希望执行他认为的良好实践。

这也将起作用(不进行类型转换):

 DT[, c := ifelse(v1 < 0 & v2 > 0, as.numeric(min(-v1, v2)), 0), by = list(date, id)]  # 1

或者:

 DT[, c := ifelse(v1 < 0 & v2 > 0, min(-v1, v2), 0L), by = list(date, id)] # 2

但是您不能连续运行最后两行-#1和#2-必须先删除c列。 DT$c在第一种情况下为数字,在第二种情况下为整数。

一些其他实验

DT[, c:= NULL] 
DT[, c := ifelse(v1 < 0, v1, 0), by = list(date, id)] 
# error but DT$c col created with first element as NA
# the condition was FALSE for the first element, so numeric 0 became the first element of c
# ... but the next element would be integer, hence the error
DT$c # [1]  0 NA NA NA NA NA NA NA NA
DT[, c:= NULL] 
DT[, c := ifelse(v1 > 0, v1, 0), by = list(date, id)]
# error; DT$c column is integer, with 5 as first element and the rest as NA 
DT$c # [1]  5 NA NA NA NA NA NA NA NA
DT[, c:= NULL] 
DT[, c := ifelse(v1 < 0, as.numeric(v1), 0), by = list(date, id)] 
# works without error but results in numeric DT$c
is.numeric(DT$c) # TRUE
DT[, c := ifelse(v1 < 0, v1, 0L), by = list(date, id)]
# type error, DT$c was numeric and we are trying to add an integer column
DT[, c:= NULL] # deleting the c column again
DT[, c := ifelse(v1 < 0, v1, 0L), by = list(date, id)]
# no error now
is.integer(DT$c) # TRUE