2010-06-16 36 views
10

Khi tạo các chức năng sử dụng strsplit, đầu vào vector không hoạt động như mong muốn và cần sử dụng sapply. Điều này là do đầu ra danh sách mà strsplit tạo ra. Có cách nào để vector hóa quá trình - đó là, hàm tạo ra phần tử đúng trong danh sách cho từng phần tử của đầu vào?Làm thế nào để vector hóa R strsplit?

Ví dụ, để đếm độ dài của các từ trong một vector nhân vật:

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 

Lý tưởng nhất, một cái gì đó giống như length(strsplit(words,"")[[.]]) nơi . được giải thích như là là một phần liên quan của vector đầu vào.

Trả lời

19

Nói chung, bạn nên cố gắng sử dụng chức năng vectơ để bắt đầu. Sử dụng strsplit sẽ thường xuyên yêu cầu một số loại lặp lại sau đó (sẽ chậm hơn), vì vậy hãy cố gắng tránh nó nếu có thể. Trong ví dụ của bạn, bạn nên sử dụng nchar thay vì:

> nchar(words) 
[1] 1 5 5 3 

Tổng quát hơn, tận dụng lợi thế của một thực tế rằng strsplit trả về một danh sách và sử dụng lapply:

> as.numeric(lapply(strsplit(words,""), length)) 
[1] 1 5 5 3 

Hoặc người nào khác sử dụng một chức năng l*ply gia đình từ plyr . Ví dụ:

> laply(strsplit(words,""), length) 
[1] 1 5 5 3 

Edit:

Trong danh dự của Bloomsday, tôi quyết định để kiểm tra việc thực hiện các phương pháp sử dụng Joyce của Ulysses:

joyce <- readLines("http://www.gutenberg.org/files/4300/4300-8.txt") 
joyce <- unlist(strsplit(joyce, " ")) 

Bây giờ tôi có tất cả các từ , chúng tôi có thể đếm số lượng:

> # 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 

Chức năng vectơ hóa và lapply nhanh hơn đáng kể so với phiên bản sapply gốc. Tất cả các giải pháp trả về cùng một câu trả lời (như được thấy bởi đầu ra tóm tắt).

Dường như phiên bản mới nhất của plyr nhanh hơn (đây là phiên bản cũ hơn một chút).

+0

Cảm ơn Shane, nhưng tôi không nhận được kết quả tương tự từ những gì tôi đang làm. Nó thực hiện một chương trình chữ số kiểm tra Verhoeff. Tôi đã sửa đổi chức năng của mình để tương thích với việc triển khai ở trên, nhưng với đầu vào của một vectơ dài 100.000, tôi nhận được danh sách 8 phần tử từ phần tử đầu tiên và vectơ của 8 phần tử từ phần tử thứ hai (8 là độ dài có khả năng của các phần tử vectơ). – James

+0

@ James: Sau đó, tôi sẽ tưởng tượng rằng phải có một cái gì đó khác đang xảy ra với chức năng của bạn. Như bạn có thể thấy ở trên, tôi đã thử nghiệm điều này trên một vectơ với hơn 270k bản ghi và có cùng kết quả từ mỗi bản ghi. Bạn có thể thử cung cấp thêm mã của bạn hoặc người khác cung cấp một số dữ liệu của bạn. – Shane

+0

Ngẫu nhiên, tôi chỉ cài đặt phiên bản plyr 0.1.9 trong R 2.11.1 và có thời gian tương tự như ở trên. – Shane

Các vấn đề liên quan