Saya ingin menemukan, katakanlah, 10 kata yang paling umum dalam file teks. Pertama, solusi harus dioptimalkan untuk penekanan tombol (dengan kata lain - waktu saya). Kedua, untuk kinerja. Inilah yang saya miliki sejauh ini untuk mendapatkan 10 besar:
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
Saya bisa membuat program java, python, dll. Di mana saya menyimpan (kata, numberOfOccurences) dalam kamus dan mengurutkan nilainya atau saya bisa menggunakan MapReduce, tetapi saya mengoptimalkan untuk penekanan tombol.
Adakah yang salah positif? Apakah ada cara yang lebih baik?
command-line
shell-script
Lukasz Madon
sumber
sumber
Jawaban:
Itu cukup banyak cara yang paling umum untuk menemukan "N hal yang paling umum", kecuali Anda melewatkan a
sort
, dan Anda punya uang gratiscat
:Jika Anda tidak memasukkan kata
sort
sebelum,uniq -c
Anda mungkin akan mendapatkan banyak kata tunggal palsu.uniq
hanya menjalankan garis yang unik, bukan keseluruhan uniquness.EDIT: Saya lupa tipuan, "hentikan kata-kata". Jika Anda melihat teks bahasa Inggris (maaf, satu bahasa Amerika Utara satu bahasa di sini), kata-kata seperti "dari", "dan", "yang" hampir selalu menempati posisi dua atau tiga teratas. Anda mungkin ingin menghilangkannya. Distribusi GNU Groff memiliki file bernama
eign
di dalamnya yang berisi daftar kata-kata berhenti yang lumayan bagus. Distro Arch saya sudah/usr/share/groff/current/eign
, tapi saya pikir saya juga pernah melihat/usr/share/dict/eign
atau/usr/dict/eign
di Unix lama.Anda dapat menggunakan kata-kata berhenti seperti ini:
Dugaan saya adalah bahwa sebagian besar bahasa manusia memerlukan "kata-kata berhenti" yang sama dihapus dari penghitungan frekuensi kata yang bermakna, tetapi saya tidak tahu harus menyarankan di mana bahasa lain menghentikan daftar kata-kata yang berhenti.
EDIT:
fgrep
harus menggunakan-w
perintah, yang memungkinkan pencocokan seluruh kata. Ini menghindari kesalahan positif pada kata-kata yang hanya berisi karya berhenti pendek, seperti "a" atau "i".sumber
cat
menambahkan beberapa overhead kinerja yang signifikan? Saya suka sintaksis pipa. Apa yang dilakukan * dalam '[\ n *]'?find
output? Artinya, pisahkan kata-kata/
alih-alih karakter spasi dan sejenisnya.find somewhere optoins | tr '/' '\n' | sort | uniq -c | sort -k1.1nr | head -10
Ini berfungsi lebih baik dengan utf-8:
sumber
Mari kita gunakan AWK!
Fungsi ini mencantumkan frekuensi setiap kata yang muncul dalam file yang disediakan dalam urutan menurun:
Anda dapat menyebutnya di file Anda seperti ini:
dan untuk 10 kata teratas:
Sumber: Ruby AWK-ward
sumber
Mari kita gunakan Haskell!
Ini berubah menjadi perang bahasa, bukan?
Pemakaian:
Kalau tidak:
sumber
sort | uniq -c | sort -nr
.Text
atauByteString
sebaliknya, yang sesederhana mengimpornya memenuhi syarat dan mengawali fungsi dengan kualifikasi.Sesuatu seperti ini harus bekerja menggunakan python yang biasanya tersedia:
Ini mengasumsikan kata per baris. Jika ada lebih banyak, pemisahan juga harus mudah.
sumber
cat README.md | python -c 'import collections, sys, pprint; pprint.pprint(collections.Counter(sys.stdin));'
Ini adalah masalah klasik yang mendapat resonansi pada tahun 1986, ketika Donald Knuth menerapkan solusi cepat dengan hash mencoba dalam program sepanjang 8 halaman untuk menggambarkan teknik pemrograman melek hurufnya, sementara Doug McIlroy, ayah baptis pipa Unix, merespons dengan satu-liner, itu tidak secepat, tetapi menyelesaikan pekerjaan:
Tentu saja, solusi McIlroy memiliki kompleksitas waktu O (N log N), di mana N adalah jumlah total kata. Ada banyak solusi yang lebih cepat. Sebagai contoh:
Berikut ini adalah implementasi C ++ dengan kompleksitas waktu batas atas O ((N + k) log k), biasanya - hampir linier.
Di bawah ini adalah implementasi Python cepat menggunakan kamus hash dan tumpukan dengan kompleksitas waktu O (N + k log Q), di mana Q adalah sejumlah kata unik:
Perbandingan waktu CPU (dalam detik):
Catatan:
sumber