在R中压缩矩阵

时间:2014-08-15 22:26:44

标签: r

我已经加载了一个包含2,200列的整数数据表。我想做的是通过平均每5列中的值并将其放在新表中的新列中来缩小数据。

例如,如果我有:

Col1 | Col2 | Col3 | Col4 | Col5 | Col6 | Col7 | Col8 | Col9 | Col10
  2      4      6      8     10     12     14     16     18     20

我会得到:

Col1 | Col2
  6     16 

这只是Col1中原始表中第1-5列中的值的平均值,以及Col2中第6-10列中值的平均值。

我还没有完全围绕R语法,所以任何帮助都会受到赞赏。

5 个答案:

答案 0 :(得分:3)

如果要分组的元素数量可以被n整除(在您的情况下为5),则可采用以下一种方法:

x <- 1:100
n <- 5
tapply(x, rep(seq(1, length(x), n), each=n), mean)

 # 1  6 11 16 21 26 31 36 41 46 51 56 61 66 71 76 81 86 91 96 
 # 3  8 13 18 23 28 33 38 43 48 53 58 63 68 73 78 83 88 93 98 

第一行输出包含元素名称,第二行包含连续n个元素组的方法。

要将其应用于矩阵或data.frame的所有行,您可以这样做,例如:

m <- matrix(1:1000, ncol=100)
apply(m, 1, function(x) tapply(x, rep(seq(1, length(x), n), each=n), mean))

修改

由于使用rowMeans进行矢量化,这种替代方法可以带来一些性能提升:

t(mapply(function(x, y) rowMeans(m[, x:y]),
         seq(1, ncol(m), n), seq(n, ncol(m), n)))

答案 1 :(得分:3)

哎呀,我看到这是@jiums答案中@ user20650的评论。 rowsum函数按矩量分割矩阵的行,并对每个分割的列求和。

m <- matrix(1:1000, ncol=100)
n <- 5

我们有

rowsum(t(m), rep(seq_len(ncol(m) / n), each=n)) / n

这很快,如果这很重要

library(microbenchmark)
f0 = function(m, n) rowsum(t(m), rep(seq_len(ncol(m) / n), each=n)) / n
f1 = function(m, n) 
    apply(m, 1, function(x) tapply(x, rep(seq(1, length(x), n), each=n), mean))
f2 = function(m, n)
    t(mapply(function(x, y) rowMeans(m[, x:y]),
        seq(1, ncol(m), n), seq(n, ncol(m), n)))

all.equal(f0(m, n), f1(m, n), check.attributes=FALSE)
## [1] TRUE

all.equal(f0(m, n), f2(m, n), check.attributes=FALSE)
## [1] TRUE    

microbenchmark(f0(m, n), f1(m, n), f2(m, n))
## Unit: microseconds
##      expr      min        lq   median        uq      max neval
##  f0(m, n)  164.351  170.1675  176.730  187.8570  237.419   100
##  f1(m, n) 8060.639 8513.3035 8696.742 8908.5190 9771.019   100
##  f2(m, n)  540.894  588.3820  603.787  634.1615  732.209   100

答案 2 :(得分:1)

这是使用循环和rowMeans的另一种方法,以防您在这种情况下更喜欢循环。将适用于矩阵,但需要调整矢量。

# example data
dat <- as.data.frame( matrix(1:20,ncol=10,byrow=TRUE) )
# pick range
range <- 5

ind <- seq(1,ncol(dat),range)
newdat <- NULL

for(i in ind){
  newcol <- rowMeans(dat[,i:(i+range-1)])
  newdat <- cbind(newdat, newcol)
}

将导致:

> newdat
     newcol newcol
[1,]      3      8
[2,]     13     18

答案 3 :(得分:1)

@jbaums答案看起来很不错。由于我已经开始这个答案,我想我也会发布我的解决方案。

#Make some fake data
require(data.table)
data <- data.table(t(iris[,1:4]))

#Transpose since rows are easier to deal with than columns
data <- data.table(t(data))
data[ , row := .I]

#Sum by every 5 rows
data <- data[ , lapply(.SD,sum), by=cut(row,seq(0,nrow(data),5))]

#Transpose back to original results
result <- data.table(t(data))

答案 4 :(得分:1)

如果您希望从col1-col5col6-col10等获取元素的方法

m1 <- matrix(c(rep(1:100, 2), 1:20), ncol=22)
n <- 5
p1 <- prod(dim(m1))
n1 <- nrow(m1)*n
n2 <- p1-p1%%n1

c(rowMeans(matrix(m1[1:n2], nrow=p1%/%n1, byrow=TRUE)), mean(m1[(n2+1):p1]))
#[1]  25.5 75.5 25.5 75.5 10.5

或者

 sapply(seq(1,ncol(m1), by=n), function(i) mean(m1[,i:(min(c(i+n-1), ncol(m1)))]) )
 #[1] 25.5 75.5 25.5 75.5 10.5

带一些标签

 indx <- seq(1,n2/nrow(m1), by=n)
 indx1 <- paste("Col",paste(indx, indx+4, sep="-"),sep="_")
 indx2 <- paste("Col", paste(seq(p1%%n1+1, ncol(m1)),collapse="-"), sep="_")
 c(rowMeans(matrix(m1[1:n2], nrow=p1%/%n1, byrow=TRUE, dimnames=list(indx1, NULL))), setNames(mean(m1[(n2+1):p1]), indx2))
 # Col_1-5  Col_6-10 Col_11-15 Col_16-20 Col_21-22 
 #  25.5      75.5      25.5      75.5      10.5 

更新

我意识到您希望rowMeans分割列1:56:1011:15等。如果是这样的话:

 res1 <- cbind( colMeans(aperm(array(m1[1:n2], dim=c(nrow(m1), n, p1%/%n1)), c(2,1,3))),
                 rowMeans(m1[,(ncol(m1)-ncol(m1)%%n+1):ncol(m1)]))

等于手动拆分列

 res2 <- cbind(rowMeans(m1[,1:5]), rowMeans(m1[,6:10]), rowMeans(m1[,11:15]), 
              rowMeans(m1[,16:20]), rowMeans(m1[,21:22]))
   identical(res1,res2)
  #[1] TRUE

  colnames(res1) <- c(indx1,indx2)
  res1
  #     Col_1-5 Col_6-10 Col_11-15 Col_16-20 Col_21-22
  #[1,]      21       71        21        71         6
  #[2,]      22       72        22        72         7
  #[3,]      23       73        23        73         8
  #[4,]      24       74        24        74         9
  #[5,]      25       75        25        75        10
  #[6,]      26       76        26        76        11
  #[7,]      27       77        27        77        12
  #[8,]      28       78        28        78        13
  #[9,]      29       79        29        79        14
 #[10,]      30       80        30        80        15