एक फ़ाइल में n सबसे अधिक बार शब्द खोजें


34

मैं एक पाठ फ़ाइल में 10 सबसे सामान्य शब्द ढूंढना, कहना चाहता हूं। सबसे पहले, समाधान कीस्ट्रोक्स (दूसरे शब्दों में - मेरे समय) के लिए अनुकूलित किया जाना चाहिए। दूसरे, प्रदर्शन के लिए। यहाँ मैं क्या शीर्ष 10 पाने के लिए अब तक है:

cat test.txt | tr -c '[:alnum:]' '[\n*]' | uniq -c | sort -nr | head  -10
  6 k
  2 g
  2 e
  2 a
  1 r
  1 k22
  1 k
  1 f
  1 eeeeeeeeeeeeeeeeeeeee
  1 d

मैं एक जावा, अजगर आदि कार्यक्रम बना सकता हूं, जहां मैं एक शब्दकोश में शब्द (संख्या, संख्या) को संग्रहीत करता हूं और मान को सॉर्ट करता हूं या मैं MapReduce का उपयोग कर सकता हूं, लेकिन मैं कीस्ट्रोक्स के लिए अनुकूलन करता हूं।

क्या कोई झूठी सकारात्मकता है? क्या कोई बेहतर तरीका है?


आप आखिर में -10 क्यों लगाएंगे? : पी
अनु

जवाबों:


47

"एन सबसे सामान्य चीजें" खोजने का सबसे आम तरीका बहुत सुंदर है, सिवाय इसके कि आप एक को याद कर रहे हैं sort, और आपको एक आभारी मिल गया है cat:

tr -c '[:alnum:]' '[\n*]' < test.txt | sort | uniq -c | sort -nr | head  -10

यदि आप एक में डाल नहीं है, तो sortइससे पहले कि uniq -c आप शायद गलत सिंगलटन शब्द का एक बहुत मिल जाएगा। uniqकेवल रेखाओं के अनूठे रन ही होते हैं, समग्रता से नहीं।

संपादित करें: मैं एक चाल भूल गया, "शब्दों को रोकें"। यदि आप अंग्रेजी पाठ (क्षमा करें, अखंड उत्तर अमेरिकी यहाँ देख रहे हैं), "की", "और", "" जैसे शब्द हमेशा शीर्ष दो या तीन स्थानों पर लेते हैं। आप शायद उन्हें खत्म करना चाहते हैं। GNU ग्रॉफ वितरण में एक फ़ाइल eignहै, जिसमें स्टॉप शब्दों की एक अच्छी सभ्य सूची है। मेरा आर्क डिस्ट्रो है /usr/share/groff/current/eign, लेकिन मुझे लगता है कि मैंने भी देखा है /usr/share/dict/eignया/usr/dict/eign पुराने यूनिक्स में ।

आप इस तरह से रोक शब्दों का उपयोग कर सकते हैं:

tr -c '[:alnum:]' '[\n*]' < test.txt |
fgrep -v -w -f /usr/share/groff/current/eign |
sort | uniq -c | sort -nr | head  -10

मेरा अनुमान है कि अधिकांश मानव भाषाओं को सार्थक शब्द आवृत्ति गणनाओं से हटाए गए समान "स्टॉप वर्ड्स" की आवश्यकता है, लेकिन मुझे नहीं पता कि अन्य भाषाओं को शब्दों की सूची को रोकने के लिए कहां सुझाव देना है।

EDIT: कमांड का fgrepउपयोग करना चाहिए -w, जो पूरे शब्द मिलान को सक्षम करता है। यह उन शब्दों पर झूठी सकारात्मकता से बचता है जिनमें केवल "स्टॉप" या "i" जैसे लघु स्टॉप कार्य होते हैं।


2
क्या catकुछ महत्वपूर्ण प्रदर्शन ओवरहेड जोड़ते हैं? मुझे पाइप सिंटैक्स पसंद है। '[\ N *]' में * क्या करता है?
लुकाज़ मेडन

1
यदि आपको "cat test.txt" पसंद है, तो हर तरह से इसका उपयोग करें। मैंने कुछ जगह एक लेख पढ़ा है जहाँ डेनिस रिची कहते हैं कि "कैट समथिंग। समथेल्सी" सिंटैक्स का अधिक व्यापक रूप से उपयोग किया जाता है, और यह कि '<कुछ' सिंटैक्स एक गलती का कुछ था, क्योंकि यह एकल उद्देश्य है।
ब्रूस एडिगर

क्या होगा यदि मैं किसी findआउटपुट में सबसे सामान्य निर्देशिका नाम ढूंढना चाहता हूं ? यही है, /व्हॉट्सएप के पात्रों और समान के बजाय शब्दों को विभाजित करें ।
erb

1
@ हर्ब - आप शायद कुछ ऐसा करेंगे:find somewhere optoins | tr '/' '\n' | sort | uniq -c | sort -k1.1nr | head -10
ब्रूस एडगर

1
@erb - सवाल के रूप में पूछें, टिप्पणी में नहीं। आपके पास अपने प्रश्न को फ्रेम करने के लिए अधिक जगह होगी, ताकि आपको आवश्यक उत्तर मिल सके। उदाहरण इनपुट, और वांछित आउटपुट दें। आपको एक अच्छा सवाल पूछने के लिए कुछ प्रतिष्ठा अंक मिल सकते हैं, और मुझे एक टिप्पणी में बेहतर जवाब देने के लिए अंक मिलेंगे।
ब्रूस एडिगर


7

चलो AWK का उपयोग करें!

यह फ़ंक्शन अवरोही क्रम में प्रदान की गई फ़ाइल में होने वाले प्रत्येक शब्द की आवृत्ति को सूचीबद्ध करता है:

function wordfrequency() {
  awk '
     BEGIN { FS="[^a-zA-Z]+" } {
         for (i=1; i<=NF; i++) {
             word = tolower($i)
             words[word]++
         }
     }
     END {
         for (w in words)
              printf("%3d %s\n", words[w], w)
     } ' | sort -rn
}

आप इसे अपनी फ़ाइल पर इस तरह से कॉल कर सकते हैं:

$ cat your_file.txt | wordfrequency

और शीर्ष 10 शब्दों के लिए:

$ cat your_file.txt | wordfrequency | head -10

स्रोत: AWK- वार्ड रूबी


4

हास्केल का उपयोग करते हैं!

यह एक भाषा युद्ध में बदल रहा है, है ना?

import Data.List
import Data.Ord

main = interact $ (=<<) (\x -> show (length x) ++ " - " ++ head x ++ "\n")
                . sortBy (flip $ comparing length)
                . group . sort
                . words

उपयोग:

cat input | wordfreq

वैकल्पिक रूप से:

cat input | wordfreq | head -10

मामले को अनदेखा करने का एक संशोधित संस्करण: pastebin.com/57T5B6BY
एक्सल लाटवाला

क्लासिक की तुलना में बहुत धीमा काम करता है sort | uniq -c | sort -nr
एंड्री मकुखा

@AndriyMakukha अड़चन यह है कि तार हास्केल में पात्रों की सूची से जुड़े हैं। हम सी-जैसी गति प्राप्त कर सकते हैं Textया ByteStringइसके बजाय स्विच करके , जो कि योग्य के रूप में इसे आयात करने और क्वालिफायर के साथ फ़ंक्शन को प्रीफ़िक्स करने के रूप में सरल है।
ब्लैकपैक

pastebin.com/QtJjQwT9 काफी तेजी से संस्करण, पठनीयता के लिए लिखा
BlackCap

3

कुछ इस तरह से अजगर का उपयोग करके काम करना चाहिए जो आमतौर पर उपलब्ध है:

cat slowest-names.log | python -c 'import collections, sys; print collections.Counter(sys.stdin);'

यह प्रति पंक्ति शब्द मानता है। यदि अधिक हैं, तो विभाजन आसान होना चाहिए।


python3 और nicer आउटपुटcat README.md | python -c 'import collections, sys, pprint; pprint.pprint(collections.Counter(sys.stdin));'
लुकाज़

1

यह एक क्लासिक समस्या है, जिसे 1986 में कुछ प्रतिध्वनि मिली थी, जब डोनाल्ड नुथ ने अपनी साहित्यिक प्रोग्रामिंग तकनीक को चित्रित करने के लिए 8-पेज लंबे कार्यक्रम में हैश कोशिशों के साथ एक तेज़ समाधान लागू किया , जबकि यूनिक्स पाइप के गॉडफादर डग मैकलीरो ने जवाब दिया। एक-लाइनर, जो जल्दी नहीं था, लेकिन काम पूरा हो गया:

tr -cs A-Za-z '\n' | tr A-Z a-z | sort | uniq -c | sort -rn | sed 10q

बेशक, मैकलॉयर के समाधान में समय जटिलता ओ (एन लॉग एन) है, जहां एन कुल शब्दों की संख्या है। ज्यादा तेज उपाय हैं। उदाहरण के लिए:

यहां ऊपरी सी टाइम जटिलता ओ ((एन + के) लॉग के) के साथ एक सी ++ कार्यान्वयन है, आमतौर पर - लगभग रैखिक।

नीचे एक तेज़ पायथन कार्यान्वयन है जो समय जटिलता ओ (एन + के लॉग क्यू) के साथ हैश शब्दकोशों और ढेर का उपयोग कर रहा है, जहां क्यू कई अद्वितीय शब्द हैं:

import collections, re, sys

filename = sys.argv[1]
k = int(sys.argv[2]) if len(sys.argv)>2 else 10

text = open(filename).read()
counts = collections.Counter(re.findall('[a-z]+', text.lower()))
for i, w in counts.most_common(k):
    print(i, w)

CPU समय की तुलना (सेकंड में):

                                     bible32       bible256
C++ (prefix tree + heap)             5.659         44.730  
Python (Counter)                     10.314        100.487
Sheharyar (AWK + sort)               30.864        251.301
McIlroy (tr + sort + uniq)           60.531        690.906

टिप्पणियाँ:

  • बाइबिल को बाइबिल 32 बार (135 एमबी), बाइबिल 256 - क्रमशः 256 बार (1.1 जीबी) के साथ संक्षिप्त किया गया है।
  • पायथन लिपियों की गैर-रेखीय धीमी गति से पूरी तरह से इस तथ्य के कारण होता है कि यह पूरी तरह से मेमोरी में फाइलों को संसाधित करता है, इसलिए ओवरहेड्स बड़ी फ़ाइलों के लिए बड़े हो रहे हैं।
  • यदि एक यूनिक्स उपकरण था जो ढेर का निर्माण कर सकता है और ढेर के ऊपर से n तत्वों को उठा सकता है, तो AWK समाधान निकट-रैखिक समय जटिलता प्राप्त कर सकता है, जबकि वर्तमान में यह O (N + Q log Q) है।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.