找到矩阵行的中位数和绝对偏差

时间:2011-05-27 14:37:24

标签: r matrix

我的数据框有22239行& 200列。第一列 - NAME - 是一个字符,其他列是数字。我的目标是通过以下方式对行的所有元素进行操作:

  • 查找行的中位数;
  • 从行元素(值)中减去中位数;
  • 查找行中位数绝对偏差(mad);
  • 按行划分行元素。

我试过这种方式

edata <- read.delim("a.txt", header=TRUE, sep="\t")

## Converting dataframe into Matrix
## Taking all rows but starting from 2 column to 200
data <- as.matrix(edata[,2:200]) 
for(i in 1:22239){  #rows below columns
    for(j in 1:200) {
        m <- median(data[i,]) # median of rows
        md <- mad(normdata[i,]) # mad of rows
        a <- data[i,j]  # assigning matrix element value to a
        subs = a-m    # substracting
        escore <- subs/md  # final score
        data[i,j] <- escore  # assigning final score to row elements

获取行的每个元素的新值后,我想根据NAME列的75%分位数对其进行排序。但是,我不知道该怎么做。

我知道我的代码不是内存有效的。当我运行上面的代码时,循环非常慢。尝试foreach,但无法成功。你们能告诉我处理这类问题的好方法吗?

5 个答案:

答案 0 :(得分:3)

这是sweep()的理想工作。

set.seed(47)
dat <- matrix(rnorm(22239 * 200), ncol = 200)
rmeds <- apply(dat, 1, median)     ## row medians
rmads <- apply(dat, 1, mad)        ## row mads
dat2 <- sweep(dat, 1, rmeds, "-")  ## sweep out the medians
dat2 <- sweep(dat2, 1, rmads, "/") ## sweep out the mads

这可以通过不使用mad()来加速,因为它再次计算中位数:

rmeds <- apply(dat, 1, median)     ## row medians
dat3 <- sweep(dat, 1, rmeds, "-")  ## sweep out the medians
rmads <- 1.4826 * apply(abs(dat3), 1, median)        ## row mads
dat3 <- sweep(dat3, 1, rmads, "/") ## sweep out the mads

R> all.equal(dat2, dat3)
[1] TRUE

请注意,R的mad()乘以常数1.4826以实现渐近正常的一致性,因此在第二个示例中为额外的位。

我系统上的一些时间安排:

## first version
   user  system elapsed 
  6.215   0.183   6.412 

## second version
   user  system elapsed 
  4.365   0.167   4.535 

对于@ Nick的回答我得到了:

## @Nick's Version
   user  system elapsed 
  5.900   0.032   5.955

一直比我的第一个版本快,但比第二个版本慢一点,因为中位数被计算两次。

答案 1 :(得分:2)

这个怎么样: (我创建了另一个矩阵,但方法是相同的)

dta<-matrix(rnorm(200), nrow=20)
dta.perrow<-apply(dta, 1, function(currow){c(med=median(currow), mad=mad(currow))})
result<-(dta - dta.perrow[1,])/dta.perrow[2,]

我确信还有更好的方法,但HTH。

答案 2 :(得分:1)

R与matlab一样,针对矢量运算进行了优化。你的for循环可能是实现这一目标的最慢方法。可以使用apply函数计算每行的中位数,而不是for循环。这将为您提供中位数的列向量。 e.g。

apply(edata,1,median)

类似的方法可用于其他措施。请记住,避免使用R / matlab中的for循环通常会加快代码的速度。

答案 3 :(得分:1)

您有处理行数据的特殊功能,但我喜欢使用apply。您可以将apply视为for循环(实质上是)一次处理一行。

my.m <- matrix(runif(100), ncol = 5)
my.median <- apply(X = my.m, MARGIN = 1, FUN = median) #1
my.m - my.median #2
my.mad <- apply(X = my.m, MARGIN = 1, FUN = mad) #3
my.m/my.mad #4

答案 4 :(得分:1)

您可以将所有步骤放入功能并仅使用一个应用循环。

rfun <- function(x) {
         me<- median(x)
         md<-mad(x,center=me,constant=1)
         return((x-me)/md)}

dat_s <- apply(dat,1,rfun)