根据条件重复计算

时间:2016-11-29 16:21:46

标签: r loops

我想做的很简单。但是,我是R的新手,并没有学到很多关于循环和函数的知识,也不确定获得结果的最有效方法是什么。基本上,我想计算满足我条件的行数并进行除法。这是一个例子:

B/C/D

我的分子标准是在>0Main时计算>0的{​​{1}}个数;对于分母,请计算B/C/D!= 0Main的{​​{1}}的数量。我可以使用!= 0分别获取每列的比率。但我的数据集有更多的列,我想知道是否有办法同时获得这些比率,以便我的结果如下:

length(which(df1$Main >0 & df1$B>0)) / length(which(df1$Main !=0 & df1$B !=0))

4 个答案:

答案 0 :(得分:2)

使用apply:

 apply(df1[,-1], 2, function(x) length(which(df1$Main >0 & x>0)) / length(which(df1$Main !=0 & x !=0)))

答案 1 :(得分:2)

您可以执行此向量化(不需要applyfor):

tail(colSums(df[df$Main>0,]>0, na.rm = T) / colSums(df[df$Main!=0,]!=0, na.rm = T), -1)

#        B         C         D 
#0.2000000 0.6000000 0.3333333 

答案 2 :(得分:1)

criteria1 <- df1[which(df1$Main > 0), -1] > 0
criteria2 <- df1[which(df1$Main != 0), -1] != 0
colSums(criteria1, na.rm = T)/colSums(criteria2, na.rm = T)
##         B         C         D 
## 0.2000000 0.6000000 0.3333333

编辑:看来Niek的方法对于这个特定的数据来说是最快的

# Unit: microseconds
#            expr     min       lq     mean   median       uq      max neval
#        Jim(df1) 216.468 230.0585 255.3755 239.8920 263.6870  802.341   300
# emilliman5(df1) 120.109 135.5510 155.9018 142.4615 156.0135 1961.931   300
#       Niek(df1)  97.118 107.6045 123.5204 111.1720 119.6155 1966.830   300
#     nine89(df1) 211.683 222.6660 257.6510 232.2545 252.6570 2246.225   300
#[[1]]
#          [,1]    [,2]     [,3]    [,4]
#median 239.892 142.462  111.172 232.255
#ratio    1.000   0.594    0.463   0.968
#diff     0.000 -97.430 -128.720  -7.637

但是,当有很多列时,矢量化方法会更快。

Nrow <- 1000
Ncol <- 1000
mat <- matrix(runif(Nrow*Ncol),Nrow)
df1 <- data.frame(Main = sample(-2:2,Nrow,T), mat) #1001 columns

#Unit: milliseconds
#           expr      min       lq      mean    median        uq      max
#       Jim(df1) 46.75627 53.88500  66.93513  56.58143  62.04375 185.0460
#emilliman5(df1) 73.35257 91.87283 151.38991 178.53188 185.06860 292.5571
#      Niek(df1) 68.17073 76.68351  89.51625  80.14190  86.45726 200.7119
#    nine89(df1) 51.36117 56.79047  74.53088  60.07220  66.34270 191.8294

#[[1]]
#         [,1]    [,2]   [,3]   [,4]
#median 56.581 178.532 80.142 60.072
#ratio   1.000   3.155  1.416  1.062
#diff    0.000 121.950 23.560  3.491

功能

Jim <- function(df1){
    criteria1 <- df1[which(df1$Main > 0), -1] > 0
    criteria2 <- df1[which(df1$Main != 0), -1] != 0
    colSums(criteria1, na.rm = T)/colSums(criteria2, na.rm = T)
}


emilliman5 <- function(df1){
    apply(df1[,-1], 2, function(x) length(which(df1$Main >0 & x>0)) / length(which(df1$Main !=0 & x !=0)))
}

 Niek <- function(df1){
     ratio1<-vector()
     for(i in 2:ncol(df1)){
         ratio1[i-1] <- length(which(df1$Main >0 & df1[,i]>0)) / length(which(df1$Main !=0 & df1[,i] !=0))
     }
     ratio1
 }

nine89 <- function(df){
    tail(colSums(df[df$Main>0,]>0, na.rm = T) / colSums(df[df$Main!=0,]!=0, na.rm = T), -1)
}

答案 3 :(得分:1)

执行此操作的一种方法是使用for循环遍历列并应用您编写的函数。像这样:

ratio1<-vector()
for(i in 2:ncol(df1)){
ratio1[i-1] <- length(which(df1$Main >0 & df1[,i]>0)) / length(which(df1$Main !=0 & df1[,i] !=0))
}

使用apply或data.table可能有更好的方法,但这是一个我能想到的简单解决方案。适用于任意数量的列。如果您想要一个小数的答案,请使用round()