Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/80.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
data.table按行求和、平均值、最小值、最大值(如dplyr)?_R_Data.table_Dplyr - Fatal编程技术网

data.table按行求和、平均值、最小值、最大值(如dplyr)?

data.table按行求和、平均值、最小值、最大值(如dplyr)?,r,data.table,dplyr,R,Data.table,Dplyr,还有其他关于datatable上的行运算符的帖子。它们不是一个,就是一个 我这里的问题更一般。有一个使用dplyr的解决方案。我已经尝试过了,但没有找到使用data.table语法的等效解决方案。您能推荐一个优雅的data.table解决方案,它可以重现与dplyr版本相同的结果吗 编辑1:真实数据集(10MB,73000行,24个数字列的统计数据)上建议解决方案的基准汇总。基准结果是主观的。但是,经过的时间始终是可重复的 | Solution By | Speed compared to dp

还有其他关于datatable上的行运算符的帖子。它们不是一个,就是一个

我这里的问题更一般。有一个使用dplyr的解决方案。我已经尝试过了,但没有找到使用data.table语法的等效解决方案。您能推荐一个优雅的data.table解决方案,它可以重现与dplyr版本相同的结果吗

编辑1:真实数据集(10MB,73000行,24个数字列的统计数据)上建议解决方案的基准汇总。基准结果是主观的。但是,经过的时间始终是可重复的

| Solution By | Speed compared to dplyr     |
|-------------|-----------------------------|
| Metrics v1  |  4.3 times SLOWER (use .SD) |
| Metrics v2  |  5.6 times FASTER           |
| ExperimenteR| 15   times FASTER           |
| Arun v1     |  3   times FASTER (Map func)|
| Arun v2     |  3   times FASTER (foo func)|
| Ista        |  4.5 times FASTER           |
编辑2:我在一天后添加了一个计数列。这就是为什么在各种贡献者建议的解决方案中找不到本专栏的原因

数据设置

library(data.table)
dt <- data.table(ProductName = c("Lettuce", "Beetroot", "Spinach", "Kale", "Carrot"),
    Country = c("CA", "FR", "FR", "CA", "CA"),
    Q1 = c(NA, 61, 40, 54, NA), Q2 = c(22,  8, NA,  5, NA),
    Q3 = c(51, NA, NA, 16, NA), Q4 = c(79, 10, 49, NA, NA))

#    ProductName Country Q1 Q2 Q3 Q4
# 1:     Lettuce      CA NA 22 51 79
# 2:    Beetroot      FR 61  8 NA 10
# 3:     Spinach      FR 40 NA NA 49
# 4:        Kale      CA 54  5 16 NA
# 5:      Carrot      CA NA NA NA NA
data.table出错(计算整列而不是每行)

几乎是解决方案,但更复杂且缺少Q1、Q2、Q3、Q4输出列

dtmelt <- reshape2::melt(dt, id=c("ProductName", "Country"),
            variable.name="Quarter", value.name="Qty")

dtmelt[, .(AVG = mean(Qty, na.rm=TRUE),
    MIN = min (Qty, na.rm=TRUE),
    MAX = max (Qty, na.rm=TRUE),
    SUM = sum (Qty, na.rm=TRUE),
    NAcnt= sum(is.na(Qty))), by = list(ProductName, Country)]

#    ProductName Country      AVG MIN  MAX SUM NAcnt
# 1:     Lettuce      CA 50.66667  22   79 152     1
# 2:    Beetroot      FR 26.33333   8   61  79     1
# 3:     Spinach      FR 44.50000  40   49  89     2
# 4:        Kale      CA 25.00000   5   54  75     1
# 5:      Carrot      CA      NaN Inf -Inf   0     4

dtmelt您可以使用来自
matrixStats
包的高效行函数

library(matrixStats)
dt[, `:=`(MIN = rowMins(as.matrix(.SD), na.rm=T),
          MAX = rowMaxs(as.matrix(.SD), na.rm=T),
          AVG = rowMeans(.SD, na.rm=T),
          SUM = rowSums(.SD, na.rm=T)), .SDcols=c(Q1, Q2,Q3,Q4)]

dt
#    ProductName Country Q1 Q2 Q3 Q4 MIN  MAX      AVG SUM
# 1:     Lettuce      CA NA 22 51 79  22   79 50.66667 152
# 2:    Beetroot      FR 61  8 NA 10   8   61 26.33333  79
# 3:     Spinach      FR 40 NA 79 49  40   79 56.00000 168
# 4:        Kale      CA 54  5 16 NA   5   54 25.00000  75
# 5:      Carrot      CA NA NA NA NA Inf -Inf      NaN   0
对于具有500000行的数据集(使用CRAN中的
data.table

使用
by=1:nrow(dt)
,在
数据表中执行行操作

 library(data.table)
dt[, `:=`(AVG= mean(as.numeric(.SD),na.rm=TRUE),MIN = min(.SD, na.rm=TRUE),MAX = max(.SD, na.rm=TRUE),SUM = sum(.SD, na.rm=TRUE)),.SDcols=c(Q1, Q2,Q3,Q4),by=1:nrow(dt)] 
   ProductName Country Q1 Q2 Q3 Q4      AVG MIN  MAX SUM
1:     Lettuce      CA NA 22 51 79 50.66667  22   79 152
2:    Beetroot      FR 61  8 NA 10 26.33333   8   61  79
3:     Spinach      FR 40 NA 79 49 56.00000  40   79 168
4:        Kale      CA 54  5 16 NA 25.00000   5   54  75
5:      Carrot      CA NA NA NA NA      NaN Inf -Inf   0

Warning messages:
1: In min(c(NA_real_, NA_real_, NA_real_, NA_real_), na.rm = TRUE) :
  no non-missing arguments to min; returning Inf
2: In max(c(NA_real_, NA_real_, NA_real_, NA_real_), na.rm = TRUE) :
  no non-missing arguments to max; returning -Inf
您收到了警告消息,因为在第5行中,您正在计算“零”的最大值、总和、最小值和最大值。例如,请参见以下内容:

min(c(NA,NA,NA,NA),na.rm=TRUE)
[1] Inf
Warning message:
In min(c(NA, NA, NA, NA), na.rm = TRUE) :
  no non-missing arguments to min; returning Inf
另一种方法(虽然效率不高,因为每次都调用
na.omit()
,还有许多内存分配):


但正如我提到的,一旦实现了
colwise()
rowwise()
,这将变得简单得多。本例中的语法可能类似于:

dt[, rowwise(.SD, list(MIN=min, MAX=max, SUM=sum, AVG=mean), na.rm=TRUE), by = 1:nrow(dt)]
# `by = ` is really not necessary in this case.
对于这种情况,甚至更简单:

rowwise(dt, list(...), na.rm=TRUE)

编辑:

另一个变化:

myNACount <- function(x, ...) length(attributes(x)$na.action)
foo <- function(x, ...) {
    funs = c(min, max, mean, sum, myNACount)
    lapply(funs, function(f) f(x, ...))
}

dt[, (new_cols) := foo(na.omit(c(Q1, Q2, Q3, Q4)), na.rm=TRUE), by=1:nrow(dt)]
#    ProductName Country Q1 Q2 Q3 Q4 MIN  MAX      SUM AVG NAs
# 1:     Lettuce      CA NA 22 51 79  22   79 50.66667 152   1
# 2:    Beetroot      FR 61  8 NA 10   8   61 26.33333  79   1
# 3:     Spinach      FR 40 NA NA 49  40   49 44.50000  89   2
# 4:        Kale      CA 54  5 16 NA   5   54 25.00000  75   1
# 5:      Carrot      CA NA NA NA NA Inf -Inf      NaN   0   4

myNACount可以使用
apply
功能执行行计算。单独定义函数可以使事情更干净:

dstats <- function(x){
    c(mean(x,na.rm=TRUE),
      min(x, na.rm=TRUE),
      max(x, na.rm=TRUE),
      sum(x, na.rm=TRUE))
}
请注意,使用
[.data.table
进行此操作的唯一优点是允许使用
:=
通过引用快速添加


这比
matrixStats
解决方案慢但更灵活,比@Experiator的
dplyr
解决方案快,打卡时间为36秒(我对其他方法的计时与@Experiator的答案中的计时类似)。

我希望其他人遇到同样的问题时,他们可能会觉得有用

第一种方法:合并基本R 第二种方法:基于@experiator思想,使用matrixStats包
dt1
dt[,AVG:=rowMeans(.SD,na.rm=T),.SDcols=c(Q1,Q2,Q3,Q4)]
@实验者谢谢(SDcols应该是字符向量吗?)我试过这个
dt[,(Q1,Q2,Q3,Q4,AVG=rowMeans(.SD,na.rm=T),MIN=pmin(Q1,Q2,Q3,Q3,Q4,na.rm=T),MAX=pmax(Q1,Q1,Q2,Q4,na.rm=T)),.Q1,Q3=c(“,.Q4”)
,但仍然缺少SUM,并且没有产品名称和国家/地区columns@Metrics没有计算错误的输出b/c:
dt[,`:=`(AVG=rowMeans(.SD,na.rm=TRUE),MIN=MIN(.SD,na.rm=TRUE),MAX=MAX(.SD,na.rm=TRUE),SUM=SUM(.SD,na.rm=TRUE)),.SDcols=c(“Q1”,“Q2”,“Q3”,“Q4”),by=1:nrow(dt)]警告消息:1:In MIN(c(NA_real,NA_real,NA_real,NA_real,NA_real),NA.rm=TRUE):最小值没有未丢失的参数;返回Inf 2:In max(c(NA_real,NA_real,NA_real,NA_real,NA_real,NA,NA_real),NA.rm=TRUE):max没有未丢失的参数;返回-Inf
请参阅我的答案。我已更新了代码并从注释中删除。Dplyr和data.table都为NaN和-Inf发出警告。data.table尽可能使用base R函数,以避免强加“围墙花园”方法..但是基本R没有一个很好的函数来执行这个操作:-(.所以我们必须实现
colwise()
rowwise()
函数,在…下归档。我已将其标记为下一版本。同样的错误,可能是b/c我使用的是最新数据。表1.9.4(R版本3.2.0(2015-04-16))?此外,我必须将SDcols置于引号中
。SDcols=c(“Q1”、“Q2”、“Q3”、“Q4”)
以避免“找不到对象Q1”。以下是我运行代码时出现的错误:
1:In min(c(NA_real,NA_real,NA_real,NA_real),NA.rm=TRUE):min没有不丢失的参数;返回Inf 2:In max(c(NA(NA_real,NA_real,NA_real,NA_real),NA.rm=TRUE):max没有未丢失的参数;返回-Inf
这些是警告而不是错误(我也知道了)。您得到警告是因为您的输出返回无限值
-Inf
Inf
、和
NaN
(因为您取的是无值的平均值、总和、最小值和最大值)。如果您运行自己的dplyr代码,它也会发出相同的警告。我使用的是开发版本1.9.5+(您可以从github获得)。我不确定您为什么需要加引号。它运行时没有为我加引号。请在答案中查看我的更新。哦,这是真的。我忘记打印(dt)。抱歉!顺便说一句,如果我不在
中的列名周围加引号,你知道为什么我找不到
对象“Q1”
。SDcols=c(Q1,Q2,Q3,Q4)
(data.table 1.9.4,R v3.2.0)刚刚在一个10MB数据集上应用了你的解决方案,73000行。dplyr版本比你建议的实现快4倍。这可能是as.numeric(.SD)吗在平均值的计算中?你不能在如此小的数据集上进行基准测试,这是毫无意义的。是的,你为什么要在
行方式
的潜在解决方案中添加
by
?可能会出现类似
dt[,if(TRUE)do_bla else rowwise(…),by=some_cols]
(就像我说的,在这种情况下,没有必要)@Arun That
myNACount@Arun Ahem…很抱歉,我在基准测试中犯了一个错误。您所做的第二个版本比第一个版本稍快。最快的执行时间来自于实验者的解决方案。@polymer,不用担心。我想我们在这里都学到了很多:-)。很好的问题1。
apply()
convertsrequire(data.table) new_cols = c("MIN", "MAX", "SUM", "AVG") dt[, (new_cols) := Map(function(x, f) f(x), list(na.omit(c(Q1,Q2,Q3,Q4))), list(min, max, sum, mean)), by = 1:nrow(dt)] # ProductName Country Q1 Q2 Q3 Q4 MIN MAX SUM AVG # 1: Lettuce CA NA 22 51 79 22 79 152 50.66667 # 2: Beetroot FR 61 8 NA 10 8 61 79 26.33333 # 3: Spinach FR 40 NA 79 49 40 79 168 56.00000 # 4: Kale CA 54 5 16 NA 5 54 75 25.00000 # 5: Carrot CA NA NA NA NA Inf -Inf 0 NaN
dt[, rowwise(.SD, list(MIN=min, MAX=max, SUM=sum, AVG=mean), na.rm=TRUE), by = 1:nrow(dt)]
# `by = ` is really not necessary in this case.
rowwise(dt, list(...), na.rm=TRUE)
myNACount <- function(x, ...) length(attributes(x)$na.action)
foo <- function(x, ...) {
    funs = c(min, max, mean, sum, myNACount)
    lapply(funs, function(f) f(x, ...))
}

dt[, (new_cols) := foo(na.omit(c(Q1, Q2, Q3, Q4)), na.rm=TRUE), by=1:nrow(dt)]
#    ProductName Country Q1 Q2 Q3 Q4 MIN  MAX      SUM AVG NAs
# 1:     Lettuce      CA NA 22 51 79  22   79 50.66667 152   1
# 2:    Beetroot      FR 61  8 NA 10   8   61 26.33333  79   1
# 3:     Spinach      FR 40 NA NA 49  40   49 44.50000  89   2
# 4:        Kale      CA 54  5 16 NA   5   54 25.00000  75   1
# 5:      Carrot      CA NA NA NA NA Inf -Inf      NaN   0   4
dstats <- function(x){
    c(mean(x,na.rm=TRUE),
      min(x, na.rm=TRUE),
      max(x, na.rm=TRUE),
      sum(x, na.rm=TRUE))
}
(dt[,
   c("AVG", "MIN", "MAX", "SUM") := data.frame(t(apply(.SD, 1, dstats))),
   .SDcols=c("Q1", "Q2","Q3","Q4"),
])
dt[,`:=`(MIN = apply(dt[, Q1:Q4], 1, FUN = min, na.rm=TRUE),
       MAX = apply(dt[, Q1:Q4], 1, FUN = max, na.rm = TRUE),
       AVG = rowMeans(dt[, Q1:Q4], na.rm = TRUE),
       SUM = rowSums(dt[, Q1:Q4], na.rm = TRUE))][]
# ProductName Country Q1 Q2 Q3 Q4 MIN  MAX      AVG SUM
# 1:     Lettuce      CA NA 22 51 79  22   79 50.66667 152
# 2:    Beetroot      FR 61  8 NA 10   8   61 26.33333  79
# 3:     Spinach      FR 40 NA NA 49  40   49 44.50000  89
# 4:        Kale      CA 54  5 16 NA   5   54 25.00000  75
# 5:      Carrot      CA NA NA NA NA Inf -Inf      NaN   0
dt1 <- dt[,`:=`(MIN = rowMins(as.matrix(dt[, Q1:Q4]), na.rm=TRUE),
                MAX = rowMaxs(as.matrix(dt[, Q1:Q4]), na.rm = TRUE),
                AVG = rowMeans(dt[, Q1:Q4], na.rm = TRUE),
                SUM = rowSums(dt[, Q1:Q4], na.rm = TRUE))][]
# ProductName Country Q1 Q2 Q3 Q4 MIN  MAX      AVG SUM
# 1:     Lettuce      CA NA 22 51 79  22   79 50.66667 152
# 2:    Beetroot      FR 61  8 NA 10   8   61 26.33333  79
# 3:     Spinach      FR 40 NA NA 49  40   49 44.50000  89
# 4:        Kale      CA 54  5 16 NA   5   54 25.00000  75
# 5:      Carrot      CA NA NA NA NA Inf -Inf      NaN   0