2010-06-16 11 views
10

strsplit का उपयोग करने वाले फ़ंक्शंस बनाते समय, वेक्टर इनपुट वांछित व्यवहार नहीं करते हैं, और sapply का उपयोग करने की आवश्यकता है। यह सूची आउटपुट के कारण है कि strsplit उत्पादन करता है। क्या प्रक्रिया को सदिश बनाने का कोई तरीका है - यानी, फ़ंक्शन इनपुट के प्रत्येक तत्व के लिए सूची में सही तत्व उत्पन्न करता है?आर strsplit vectorize कैसे?

उदाहरण के लिए, एक चरित्र वेक्टर में शब्द की लंबाई गिनती करने के लिए:

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 

आदर्श रूप में, length(strsplit(words,"")[[.]]) की तरह कुछ जहां . इनपुट वेक्टर के प्रासंगिक हिस्सा होने के रूप में व्याख्या की है।

उत्तर

19

सामान्य रूप से, आपको प्रारंभ करने के लिए एक वेक्टरीकृत फ़ंक्शन का उपयोग करने का प्रयास करना चाहिए। strsplit का उपयोग करने के बाद अक्सर किसी प्रकार के पुनरावृत्ति की आवश्यकता होती है (जो धीमा हो जाएगा), इसलिए यदि संभव हो तो इसे टालने का प्रयास करें। अधिक आम तौर पर

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

, तथ्य यह है कि strsplit सूची लौटाता का लाभ उठाने और का उपयोग lapply: अपने उदाहरण में, आप nchar बजाय का उपयोग करना चाहिए

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

वरना plyr से एक l*ply परिवार फ़ंक्शन का उपयोग करें । उदाहरण के लिए:

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

संपादित करें: अब

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

है कि मैं सभी शब्दों है:

Bloomsday के सम्मान में, मैं जोयस के Ulysses का उपयोग कर इन तरीकों का प्रदर्शन परीक्षण करने का फैसला , हम अपनी गणना कर सकते हैं:

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

वेक्टरकृत फ़ंक्शन और lapply मूल sapply संस्करण से काफी तेज हैं। सभी समाधान एक ही जवाब लौटाते हैं (जैसा कि सारांश आउटपुट द्वारा देखा गया है)।

स्पष्ट रूप से plyr का नवीनतम संस्करण तेज़ है (यह थोड़ा पुराना संस्करण उपयोग कर रहा है)।

+0

धन्यवाद शेन, लेकिन मुझे वही परिणाम नहीं मिल रहा है जो मैं कर रहा हूं। यह Verhoeff चेक अंक योजना का कार्यान्वयन है। मैंने उपरोक्त कार्यान्वयन के साथ संगत होने के लिए अपने कार्य को संशोधित किया है, लेकिन 100,000 लंबे वेक्टर के इनपुट के साथ, मुझे पहले से 8 तत्वों की सूची मिल रही है और दूसरे से 8 तत्वों का वेक्टर (8 सबसे अधिक है वेक्टर तत्वों की संभावना लंबाई)। – James

+0

@ जेम्स: फिर मैं कल्पना करता हूं कि आपके फ़ंक्शन के साथ कुछ और होना चाहिए। जैसा कि आप ऊपर देख सकते हैं, मैंने अभी 270k से अधिक रिकॉर्ड वाले वेक्टर पर इसका परीक्षण किया और प्रत्येक से एक ही परिणाम प्राप्त किए। आप अपना अधिक कोड प्रदान करने का प्रयास कर सकते हैं या फिर अपना कुछ डेटा प्रदान कर सकते हैं। – Shane

+0

संयोग से, मैंने अभी 2.1 2.1.1 में प्लीयर संस्करण 0.1.9 स्थापित किया है और उपरोक्त में समान समय था। – Shane