按矢量,按行而不是按列划分数据帧

时间:2014-08-28 14:25:46

标签: r

我有这个数据框和向量,我想用以下行分割行:

div <- c(10,100,1000)
df <- as.data.frame(matrix(rep(1,9),nrow=3))
df <- cbind(type = as.factor(c("A","B","C")),df)
> df
  type V1 V2 V3
1    A  1  1  1
2    B  1  1  1
3    C  1  1  1

我希望以数据框形式提供答案,并保留原因。 将它与矢量分开时,我得到了“错误的”答案:

df1 <- cbind(df[,1], df[,-1]/div)
> df1
  df[, 1]    V1    V2    V3
1       A 0.100 0.100 0.100
2       B 0.010 0.010 0.010
3       C 0.001 0.001 0.001

我希望每行除以向量,而不是每列。

我的解决方法是:

divfun <- function(x){
  x / div
}

df2 <- cbind(df[,1], t(apply(df[,-1], 1, divfun)))
> df2
        V1   V2    V3
[1,] 1 0.1 0.01 0.001
[2,] 2 0.1 0.01 0.001
[3,] 3 0.1 0.01 0.001

请注意,这些因素现已丢失。

这里有两个问题:

  1. 有没有一种更简单的方法可以做到这一点,而不是为它做一个新功能?
  2. 假设没有更简单的方法,我的因素A,B和C发生了什么?我猜它与胁迫矩阵有关(因为t())?

6 个答案:

答案 0 :(得分:6)

您正在寻找的功能是sweep()

sweep(df[, -1], MARGIN = 2, div, FUN = "/")

> sweep(df[, -1], MARGIN = 2, div, FUN = "/")
   V1   V2    V3
1 0.1 0.01 0.001
2 0.1 0.01 0.001
3 0.1 0.01 0.001

因此

cbind(type = df[,1], sweep(df[, -1], 2, div, FUN = "/"))

> cbind(type = df[,1], sweep(df[, -1], 2, div, FUN = "/"))
  type  V1   V2    V3
1    A 0.1 0.01 0.001
2    B 0.1 0.01 0.001
3    C 0.1 0.01 0.001

获得所需的输出。

请注意,此处,参数MARGIN并未像1中那样引用行(2)或列(apply())。在sweep()中,它指的是与STATS对应的数组的边距,您希望扫描的向量(在这种情况下除以)。换句话说,STATS的第一个元素(在您的情况下为div)是从第1列扫出的值,STATS的第二个元素是从列中扫出的值2,等等。

答案 1 :(得分:4)

您可以使用转置功能:

> df[,2:4] <- t(t(df[,2:4]) / div)
> df
  type  V1   V2    V3
1    A 0.1 0.01 0.001
2    B 0.1 0.01 0.001
3    C 0.1 0.01 0.001

答案 2 :(得分:4)

df[,-1] <- df[,-1]/div[col(df)]
 df
#  type  V1   V2    V3
#1    A 0.1 0.01 0.001
#2    B 0.1 0.01 0.001
#3    C 0.1 0.01 0.001

str(df)
#'data.frame':  3 obs. of  4 variables:
# $ type: Factor w/ 3 levels "A","B","C": 1 2 3
# $ V1  : num  0.1 0.1 0.1
# $ V2  : num  0.01 0.01 0.01
# $ V3  : num  0.001 0.001 0.001

基准

 set.seed(454)
 dat <- as.data.frame(matrix(sample(200, 1e3*1e2, replace=TRUE), ncol=1e2))
 set.seed(29)
 div <- sample(40, 1e2, replace=TRUE)


 f1 <- function() {sweep(dat, MARGIN = 2, div, FUN = "/")}
 f2 <- function() {t(t(dat) / div)}
 f3 <- function() { mapply("/", dat, div)}
 f4 <- function() {dat/div[col(dat)]}
 f5 <- function() {for(r in 1:nrow(dat)){    
             dat[r,]/div}}

 library(microbenchmark)
 microbenchmark(f1(), f2(), f3(), f4(), f5(), unit="relative")
 #Unit: relative
 # expr         min          lq      median          uq        max neval
 # f1()    6.765024    6.724991    6.434463    5.124457   10.91735   100
 # f2()    1.000000    1.000000    1.000000    1.000000    1.00000   100
 # f3()   18.028441   18.551529   16.742279   14.239107   13.72168   100
 # f4()    6.315330    6.577099    6.333656    5.052068   10.13038   100
 # f5() 4211.839669 3908.555985 3945.130154 2962.534518 1655.12268   100

答案 3 :(得分:2)

或尝试mapply

cbind(df[, 1], mapply("/", df[, -1], div))

##        V1   V2    V3
## [1,] 1 0.1 0.01 0.001
## [2,] 2 0.1 0.01 0.001
## [3,] 3 0.1 0.01 0.001

答案 4 :(得分:2)

我喜欢David的解决方案,但我会修改它以将其转换为数据框,因为这样可以保留因子而不是获得矩阵。

data.frame(type=df[, 1], mapply("/", df[, -1], div))

#  type  V1   V2    V3
#1    A 0.1 0.01 0.001
#2    B 0.1 0.01 0.001
#3    C 0.1 0.01 0.001

这就是我想要的。

答案 5 :(得分:1)

另一种方法:

for(r in 1:nrow(df))    
    df[r,2:4]= df[r,2:4]/div
df
  type  V1   V2    V3
1    A 0.1 0.01 0.001
2    B 0.1 0.01 0.001
3    C 0.1 0.01 0.001