3

我有一个有很多列 c1 c2 c3 c4 ... c30 d 的框架

我想聚合并找到 c1..30 中唯一的所有行,然后获取该行的 min(d) 。在 sql 中,这将是由 c1、...、c30 组成的组。

d 是日期类型。

我在堆栈中找到了一些解决方案,但似乎没有一个适用于 1)这么多列 2)做一个 min 而不是 sum。

任何输入都会很棒。

4

2 回答 2

4

data.table这是使用带有一些虚假数据的包的答案:

library(data.table)

DT<-data.table(matrix(sample(1:2,3000,replace=TRUE),ncol=30))
DT2<-DT[sample(seq_len(nrow(DT)),9000,replace=TRUE)]
# EDIT: now "d" is a date.
DT2[,d:=as.POSIXct(origin = "1960-01-01",rnorm(nrow(DT2), sd = 1000))]
setnames(DT2,c(paste0("c",1:30),"d"))

## pick up herewith your own data, starting with the commented next line
# DT2 <- as.data.table(dataset)
setkeyv(DT2,paste0("c",1:30))

DT3<-DT2[,list(minD=min(d)),by=key(DT2)]

dim(DT2)
# [1] 9000   31
dim(DT3)
# [1] 100  31

马修的小补充:

+10,以及漂亮的假数据。首先设置一个键以便你可以做by=key(DT)有时会有点繁重,所以为了简单起见,我通常会做一个临时的这样的事情。但是,首先尝试最自然的事情:

DT2[,min(d),by=paste0("c",1:30)]
Error in `[.data.table`(DT2, , min(d), by = paste0("c", 1:30)) : 
    'by' appears to evaluate to column names but isn't c() or key(). Use by=
    list(...) if you can. Otherwise, by=eval(paste0("c", 1:30)) should work.
    This is for efficiency so data.table can detect which columns are needed.

错误消息告诉我们我们需要做什么:

ans = DT2[,min(d),by=eval(paste0("c",1:30))]
dim(ans)
[1] 100  31

下一个自然的想法当然是:好吧,如果 data.table 足够聪明地知道by是列名并将其放在错误消息中,为什么它不能这样做呢?答案是它只是根据数据进行猜测。在某些边缘情况下,它不是很清楚。所以目前用户需要额外的意图:用eval. 不过我对此并不完全满意,所以也许我们可以改进它。

编辑:重命名新的 data.table

在我的方法中,我在创建新列minD时通过输入

DT3<-DT2[,list(minD=min(d)),by=key(DT2)]

使用 Matthew Dowle 的方法,您可以通过输入以几乎相同的方式实现这一点

ans = DT2[,list(minD=min(d)),by=eval(paste0("c",1:30))]

如果您已经创建了该列并想要重命名它,请setnames按如下方式使用:

setnames(DT3,old="minD",new="theNewMinD")

这避免了复制整体data.table并保留了内存过度分配(使用时这两个优点都丢失了names(DT3)<-"something"),如以下文档中所述?setnames

于 2012-07-05T18:17:04.710 回答
1

未经测试,没有最小的可重现示例:

apply(unique(dataset), 1, min)

分解它:

x <- unique(dataset)  #finds only unique rows
apply(x, 1, min) # applies min across rows
                 # replace the 1 with a 2 and it applies across columns
于 2012-07-05T18:01:29.540 回答