Chcę znaleźć, powiedzmy, 10 najczęstszych słów w pliku tekstowym. Po pierwsze, rozwiązanie powinno być zoptymalizowane pod kątem naciśnięć klawiszy (innymi słowy - mojego czasu). Po drugie, za występ. Oto, co mam do tej pory, aby uzyskać 10 najlepszych:
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
Mógłbym stworzyć program Java, Python itp., W którym przechowuję (słowo, liczbaOfOccurences) w słowniku i sortuję wartość lub mogę użyć MapReduce, ale optymalizuję naciśnięcia klawiszy.
Czy są jakieś fałszywe alarmy? Czy jest lepszy sposób?
command-line
shell-script
Łukasz Madon
źródło
źródło
Odpowiedzi:
To prawie najczęstszy sposób na znalezienie „N najczęstszych rzeczy”, z tym wyjątkiem, że brakuje
sort
Ci i masz za darmocat
:Jeśli nie wpiszesz
sort
wcześniejuniq -c
, prawdopodobnie uzyskasz wiele fałszywych singletonów.uniq
robi tylko unikalne przebiegi linii, a nie ogólną unikalność.EDYCJA: Zapomniałem sztuczki „stop words”. Jeśli patrzysz na tekst w języku angielskim (przepraszam, jednojęzyczny tutaj w Ameryce Północnej), słowa takie jak „of”, „and”, „the” prawie zawsze zajmują pierwsze dwa lub trzy miejsca. Prawdopodobnie chcesz je wyeliminować. W dystrybucji GNU Groff znajduje się plik o nazwie
eign
, który zawiera całkiem przyzwoitą listę słów kluczowych. Moja dystrybucja Arch ma/usr/share/groff/current/eign
, ale myślę, że widziałem też/usr/share/dict/eign
lub/usr/dict/eign
w starych Uniksach.Możesz użyć takich słów zatrzymania:
Domyślam się, że większość ludzkich języków potrzebuje podobnych „słów kluczowych” usuniętych z liczącej częstotliwości słów, ale nie wiem, gdzie sugerować, aby uzyskać listy słów kluczowych innych języków.
EDYCJA:
fgrep
należy użyć-w
polecenia, które umożliwia dopasowanie całego słowa. Pozwala to uniknąć fałszywych trafień w słowach, które zawierają jedynie krótkie zatrzymania, takie jak „a” lub „i”.źródło
cat
powoduje znaczne zwiększenie wydajności? Lubię składnię potoku. Co robi * w '[\ n *]'?find
wyjściu? To znaczy, dziel słowa na/
znaki zamiast białych znaków i tym podobne.find somewhere optoins | tr '/' '\n' | sort | uniq -c | sort -k1.1nr | head -10
Działa to lepiej z utf-8:
źródło
Użyjmy AWK!
Ta funkcja wyświetla częstotliwość każdego słowa występującego w dostarczonym pliku w porządku malejącym:
Możesz wywołać go w swoim pliku w następujący sposób:
i dla 10 najważniejszych słów:
Źródło: AWK-ward Ruby
źródło
Użyjmy Haskell!
To zamienia się w wojnę językową, prawda?
Stosowanie:
Alternatywnie:
źródło
sort | uniq -c | sort -nr
.Text
lubByteString
zamiast, co jest tak proste, jak zaimportowanie go kwalifikowanego i poprzedzenie funkcji kwalifikatorem.Coś takiego powinno działać przy użyciu powszechnie dostępnego Pythona:
To zakłada słowo w wierszu. Jeśli jest ich więcej, podział również powinien być łatwy.
źródło
cat README.md | python -c 'import collections, sys, pprint; pprint.pprint(collections.Counter(sys.stdin));'
Jest to klasyczny problem, który zyskał rezonans w 1986 roku, kiedy Donald Knuth wdrożył szybkie rozwiązanie z hashami w 8-stronicowym programie ilustrującym jego umiejętność programowania, podczas gdy Doug McIlroy, ojciec chrzestny uniksowych rur, odpowiedział: one-liner, to nie było tak szybkie, ale wykonało zadanie:
Oczywiście rozwiązanie McIlroya ma złożoność czasową O (N log N), gdzie N jest całkowitą liczbą słów. Istnieją znacznie szybsze rozwiązania. Na przykład:
Oto implementacja C ++ z górną granicą złożoności czasowej O ((N + k) log k), zwykle - prawie liniowa.
Poniżej znajduje się szybka implementacja Pythona z użyciem słowników mieszających i sterty o złożoności czasowej O (N + k log Q), gdzie Q jest liczbą unikalnych słów:
Porównanie czasu procesora (w sekundach):
Uwagi:
źródło