Wie R strsplit vektorisieren?
-
27-09-2019 - |
Frage
Bei der Erstellung von Funktionen, dass die Verwendung strsplit
, Vektoreingaben verhalten sich nicht wie gewünscht, und sapply
Bedürfnisse verwendet werden. Dies ist auf die Liste ausgegeben, dass strsplit
erzeugt. Gibt es eine Möglichkeit, den Prozess zu vektorisieren - das ist, erzeugt die Funktion das richtige Element in der Liste für jedes der Elemente des Eingangs
Um zum Beispiel die Längen der Wörter in einem Zeichenvektor zu zählen:
words <- c("a","quick","brown","fox")
> length(strsplit(words,""))
[1] 4 # The number of words (length of the list)
> length(strsplit(words,"")[[1]])
[1] 1 # The length of the first word only
> sapply(words,function (x) length(strsplit(x,"")[[1]]))
a quick brown fox
1 5 5 3
# Success, but potentially very slow
Im Idealfall, so etwas wie length(strsplit(words,"")[[.]])
wo .
als sein dem entsprechenden Teil des Eingangsvektors interpretiert wird.
Lösung
In der Regel sollten Sie versuchen, eine vektorisiert Funktion zu verwenden, um mit zu beginnen. strsplit
verwendet, wird häufig eine Art von Iteration erfordert danach (die langsamer sein wird), so versuchen Sie es zu vermeiden, wenn möglich. In Ihrem Beispiel sollten Sie nchar
statt:
> nchar(words)
[1] 1 5 5 3
Generell nehmen sich die Tatsache zunutze, dass strsplit
eine Liste und Verwendung lapply
zurückgibt:
> as.numeric(lapply(strsplit(words,""), length))
[1] 1 5 5 3
Oder Gebrauch eine l*ply
Familie Funktion von plyr
. Zum Beispiel:
> laply(strsplit(words,""), length)
[1] 1 5 5 3
Edit:
Zu Ehren Bloomsday , entschied ich mich, die Leistung zu testen diese Ansätze Joyces Ulysses mit:
joyce <- readLines("http://www.gutenberg.org/files/4300/4300-8.txt")
joyce <- unlist(strsplit(joyce, " "))
Nun, da ich alle Worte haben, können wir unsere Zählungen tun:
> # original version
> system.time(print(summary(sapply(joyce, function (x) length(strsplit(x,"")[[1]])))))
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.000 3.000 4.000 4.666 6.000 69.000
user system elapsed
2.65 0.03 2.73
> # vectorized function
> system.time(print(summary(nchar(joyce))))
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.000 3.000 4.000 4.666 6.000 69.000
user system elapsed
0.05 0.00 0.04
> # with lapply
> system.time(print(summary(as.numeric(lapply(strsplit(joyce,""), length)))))
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.000 3.000 4.000 4.666 6.000 69.000
user system elapsed
0.8 0.0 0.8
> # with laply (from plyr)
> system.time(print(summary(laply(strsplit(joyce,""), length))))
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.000 3.000 4.000 4.666 6.000 69.000
user system elapsed
17.20 0.05 17.30
> # with ldply (from plyr)
> system.time(print(summary(ldply(strsplit(joyce,""), length))))
V1
Min. : 0.000
1st Qu.: 3.000
Median : 4.000
Mean : 4.666
3rd Qu.: 6.000
Max. :69.000
user system elapsed
7.97 0.00 8.03
Die vektorisiert Funktion und lapply
ist wesentlich schneller als die ursprüngliche Version sapply
. Alle Lösungen geben die gleiche Antwort (wie sie in der Zusammenfassung Ausgabe zu sehen ist).
Anscheinend ist die neueste Version von plyr
ist schneller (Dies ist eine etwas ältere Version verwenden).