2017-03-02 60 views
5

Rozważmy następujący czynnikLicząc liczbę „0” tego czynnika

x = factor(c("1|1","1|0","1|1","1|1","0|0","1|1","0|1")) 

chciałbym policzyć liczbę wystąpień znaku „0” tego czynnika. Jedynym rozwiązaniem znalazłem tak daleko jest

sum(grepl("0",strsplit(paste(sapply(x, as.character), collapse=""), split="")[[1]])) 
# [1] 4 

To rozwiązanie wydaje się bardzo skomplikowane dla takiego prostego procesu. Czy istnieje "lepsza" alternatywa? (Jako że proces zostanie powtórzony około 100.000 razy na czynnikach, które są 2000 elementy długo, mogę skończyć dbając o wydajność, jak również.)

Odpowiedz

7
x = factor(c("1|1","1|0","1|1","1|1","0|0","1|1","0|1")) 
x 
# [1] 1|1 1|0 1|1 1|1 0|0 1|1 0|1 
# Levels: 0|0 0|1 1|0 1|1 

sum(unlist(lapply(strsplit(as.character(x), "|"), function(x) length(grep('0', x))))) 
# [1] 4 

lub

sum(nchar(gsub("[1 |]", '', x))) 
# [1] 4 

podstawie @Rich Scriven za komentarz

sum(nchar(gsub("[^0]", '', x))) 
# [1] 4 

oparciu o użytkownika @ thelatemail komentarz - używając tabulate działa znacznie szybciej niż powyższego roztworu. Oto porównanie.

sum(nchar(gsub("[^0]", "", levels(x))) * tabulate(x)) 

Czas profilu:

x2 <- sample(x,1e7,replace=TRUE) 
system.time(sum(nchar(gsub("[^0]", '', x2)))); 
# user system elapsed 
# 14.24 0.22 14.65 
system.time(sum(nchar(gsub("[^0]", "", levels(x2))) * tabulate(x2))); 
# user system elapsed 
# 0.04 0.00 0.04 
system.time(sum(str_count(x2, fixed("0")))) 
# user system elapsed 
# 1.02 0.13 1.25 
+4

Jeśli pracujesz na bardzo dużym wektorze, możesz zaoszczędzić czas operując na 'poziomach' tylko 'x' - sum (nchar (gsub (" [^ 0] "," " , levels (x))) * tabulate (x)) ' – thelatemail

+0

@mail podziękowania. To było cudowne wiedzieć. To wszystko bije – Sathish

+1

Kluczem jest to, że 'gsub' musi działać tylko na' length (levels (x)) 'zamiast' length (x) '- regex jest dość intensywny w tym przypadku wydaje się. Powiedziawszy to wszystko, nadal jest dość szybko przetwarzać rekordy 10M w <15 sekund. – thelatemail

6

Oto trzy opcje.

Opcja 1:scan() wektora stosując sep="|"

sum(scan(text=as.character(x), sep="|") == 0) 
# [1] 4 

Opcja 2: stałą postacią gregexpr()

sum(unlist(gregexpr("0", x, fixed=TRUE)) > 0) 
# [1] 4 

Wariant 3: bardzo prosty i szybki pakowane opcja z stringr

library(stringr) 
sum(str_count(x, fixed("0"))) 
# [1] 4 
+0

Odstępy czasowe - 'set.seed (1); x2 <- sample (x, 1e7, replace = TRUE); system.time (sum (nchar (gsub ("[^ 0]", "', x2)))); system.time (sum (nchar (gsub ("[^ 0]", "", levels (x2))) * tabulat (x2))); system.time (suma (str_count (x2, fixed ("0")))) ' – thelatemail

+1

@ thebloga - To' levels' + 'tabulate' one jest marzycielska –