2016-11-29 2 views
0

Was ich versuche, ist ziemlich einfach zu tun. Allerdings bin ich neu bei R und habe nicht viel über Schleifen und Funktionen gelernt und bin mir nicht sicher, was die effizienteste Art ist, die Ergebnisse zu erhalten. Im Grunde möchte ich die Anzahl der Zeilen zählen, die meine Bedingungen erfüllen und eine Division machen. Hier ein Beispiel:Repeating Berechnung basierend auf Bedingungen

df1 <- data.frame(
    Main = c(0.0089, -0.050667, -0.030379, 0.066484, 0.006439, -0.026076), 
    B = c(NA, 0.0345, -0.0683, -0.052774, 0.014661, -0.040537), 
    C = c(0.0181, 0, -0.056197, 0.040794, 0.03516, -0.022662), 
    D = c(-0.0127, -0.025995, -0.04293, 0.057816, 0.033458, -0.058382) 
) 
df1 
# Main  B   C   D 
# 1 0.008900 NA   0.018100 -0.012700 
# 2 -0.050667 0.034500 0.000000 -0.025995 
# 3 -0.030379 -0.068300 -0.056197 -0.042930 
# 4 0.066484 -0.052774 0.040794 0.057816 
# 5 0.006439 0.014661 0.035160 0.033458 
# 6 -0.026076 -0.040537 -0.022662 -0.058382 

Meine Kriterien für den Zähler ist die Anzahl der B/C/D zu zählen, die >0 ist, wenn Main ist >0; Für Nenner, zählen die Anzahl der B/C/D die != 0 ist, wenn Main!= 0 ist. Ich kann length(which(df1$Main >0 & df1$B>0))/length(which(df1$Main !=0 & df1$B !=0)) verwenden, um die Verhältnisse für jede Spalte einzeln zu erhalten. Aber meine Datensatz viele mehr Spalten hat, und ich frage mich, ob es eine Möglichkeit ist, dieses Verhältnis auf einmal zu bekommen, so dass mein Ergebnis aussehen wird:

# B   C   D 
# 1 0.2  0.6  0.3 

Antwort

2

Nutzung gelten:

apply(df1[,-1], 2, function(x) length(which(df1$Main >0 & x>0))/length(which(df1$Main !=0 & x !=0))) 
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 

Edit: Es scheint, Niek Methode ist schnellste für diese spezifischen Daten

# 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 

wenn es jedoch viele Spalten der vektorisiert Ansatz sind schneller.

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 

Funktionen

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) 
} 
1

Eine Möglichkeit, dies zu tun, mit einer for-Schleife sein würde, die den Spalten Schleifen über und wendet die Funktion, die Sie geschrieben haben. Etwas wie folgt aus:

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)) 
} 

Vielleicht gibt es einen besseren Weg, dies zu tun, gelten mit oder data.table, aber dies ist eine einfache Lösung, die ich mit oben kommen kann. Funktioniert auf einer beliebigen Anzahl von Spalten. Verwenden Sie round(), wenn Sie die Antwort in einer Dezimalzahl wünschen.

2

Sie könnten diese vektorisiert tun (No apply oder for ist erforderlich):

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 
Verwandte Themen