Вопрос по file-io, bash – Как создать список частот каждого слова в файле?

29

У меня есть такой файл:

<code>This is a file with many words.
Some of the words appear more than once.
Some of the words only appear one time.
</code>

Я хотел бы создать список из двух столбцов. Первый столбец показывает, какие слова появляются, второй столбец показывает, как часто они появляются, например:

<code>[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
words3
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected] 
</code>
Чтобы упростить эту работу, перед обработкой списка я уберу все знаки пунктуации и заменю весь текст строчными буквами. Если нет простого решения,words а такжеword может считаться двумя отдельными словами.

Так далеко, у меня есть это:

<code>sed -i "s/ /\n/g" ./file1.txt # put all words on a new line
while read line
do
     count="$(grep -c $line file1.txt)"
     echo $line"@"$count >> file2.txt # add word and frequency to file
done < ./file1.txt
sort -u -d # remove duplicate lines
</code>

По какой-то причине это показывает только "0" после каждого слова.

Как я могу сгенерировать список каждого слова, которое появляется в файле, вместе с информацией о частоте?

Вы можете использовать хеш-таблицу для создания гистограммы или использовать Trie. James

Ваш Ответ

10   ответов
55

Неsed а такжеgrep, ноtr, sort, uniq, а такжеawk:

% (tr ' ' '\n' | sort | uniq -c | awk '{print $2"@"$1}') <<EOF
This is a file with many words.
Some of the words appear more than once.
Some of the words only appear one time.
EOF

[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
Это довольно хорошее решение. Одна вещь, которую вы, возможно, захотите сделать, это также предоставить способ удаления конечных периодов. возможно вставляя| sed -e 's/\.$//g' междуtr а такжеsort в твоем трубопроводе. mgilson
Я думал об этом, но в оригинальном сообщении говорилось, что пунктуация будет удалена до этого шага. eduffy
Ну, просто модификация вашего решения для удаления знаков препинания и прописных букв, если они не удалены. Кроме того, это удаляет ненужные пробелы, сжимает лишние пробелы и сначала печатает слова с самой высокой частотой:cat file.txt | tr '[:punct:]' ' ' | tr 'A-Z' 'a-z' | tr -s ' ' | tr ' ' '\n' | sort | uniq -c | sort -rn John Red
36

uniq -c уже делает то, что вы хотите, просто отсортируйте ввод:

a s d s d a s d s a a d d s a s d d s a' | tr ' ' '\n' | sort | uniq -c

выход

  6 a
  7 d
  7 s
Я также рекомендовал бы добавить еще одинsort -n в конце этой строки, чтобы ваш вывод был отсортирован от наименьшего к наибольшему. Wyatt
3
Давайте использовать 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

Источник: AWK-ward Ruby

одна линия:cat file | awk '{for(i=1;i<=NF;++i){D[$i]++}}END{for(k in D)print k, D[k]}' | sort -k2nr | head -n 20 mitnk
5

Содержание входного файла

$ cat inputFile.txt
This is a file with many words.
Some of the words appear more than once.
Some of the words only appear one time.

С помощьюsed | sort | uniq

$ sed 's/\.//g;s/\(.*\)/\L\1/;s/\ /\n/g' inputFile.txt | sort | uniq -c
      1 a
      2 appear
      1 file
      1 is
      1 many
      1 more
      2 of
      1 once
      1 one
      1 only
      2 some
      1 than
      2 the
      1 this
      1 time
      1 with
      3 words

uniq -ic будет считать и игнорировать регистр, но список результатов будет иметьThis вместо тогоthis.

Есть ли способ сгруппировать слова одинаковой частоты в одну строку? например «2 появляются из некоторых» вместо того, чтобы разбить их на несколько стро SasQ
2

Это может сработать для тебя:

tr '[:upper:]' '[:lower:]' <file |
tr -d '[:punct:]' |
tr -s ' ' '\n' | 
sort |
uniq -c |
sed 's/ *\([0-9]*\) \(.*\)/\[email protected]\1/'
2

Давай сделаем это в Python 3!

"""Counts the frequency of each word in the given text; words are defined as
entities separated by whitespaces; punctuations and other symbols are ignored;
case-insensitive; input can be passed through stdin or through a file specified
as an argument; prints highest frequency words first"""

# Case-insensitive
# Ignore punctuations `[email protected]#$%^&*()_-+={}[]\|:;"'<>,.?/

import sys

# Find if input is being given through stdin or from a file
lines = None
if len(sys.argv) == 1:
    lines = sys.stdin
else:
    lines = open(sys.argv[1])

D = {}
for line in lines:
    for word in line.split():
        word = ''.join(list(filter(
            lambda ch: ch not in "`[email protected]#$%^&*()_-+={}[]\\|:;\"'<>,.?/",
            word)))
        word = word.lower()
        if word in D:
            D[word] += 1
        else:
            D[word] = 1

for word in sorted(D, key=D.get, reverse=True):
    print(word + ' ' + str(D[word]))

Давайте назовем этот скрипт «quency.py »и добавим строку в« ~ / .bash_aliases »:

alias freq="python3 /path/to/frequency.py"

Теперь, чтобы найти частоту слов в вашем файле "content.txt", вы делаете:

freq content.txt

Вы также можете передать вывод на него:

cat content.txt | freq

И даже анализировать текст из нескольких файлов:

cat content.txt story.txt article.txt | freq

Если вы используете Python 2, просто замените

''.join(list(filter(args...))) сfilter(args...)python3 сpythonprint(whatever) сprint whatever
0
#!/usr/bin/env bash

declare -A map 
words="$1"

[[ -f $1 ]] || { echo "usage: $(basename $0 wordfile)"; exit 1 ;}

while read line; do 
  for word in $line; do 
    ((map[$word]++))
  done; 
done < <(cat $words )

for key in ${!map[@]}; do 
  echo "the word $key appears ${map[$key]} times"
done|sort -nr -k5
1

Для этого можно использовать tr, просто запустите

tr ' ' '\12' <NAME_OF_FILE| sort | uniq -c | sort -nr > result.txt

Пример вывода для текстового файла с названиями городов:

3026 Toronto
2006 Montréal
1117 Edmonton
1048 Calgary
905 Ottawa
724 Winnipeg
673 Vancouver
495 Brampton
489 Mississauga
482 London
467 Hamilton
1

Для сортировки требуется GNU AWK gawk). Если у вас есть еще один AWK безasort(), это можно легко отрегулировать, а затем направить наsort.

awk '{gsub(/\./, ""); for (i = 1; i <= NF; i++) {w = tolower($i); count[w]++; words[w] = w}} END {qty = asort(words); for (w = 1; w <= qty; w++) print words[w] "@" count[words[w]]}' inputfile

Разбит на несколько строк:

awk '{
    gsub(/\./, ""); 
    for (i = 1; i <= NF; i++) {
        w = tolower($i); 
        count[w]++; 
        words[w] = w
    }
} 
END {
    qty = asort(words); 
    for (w = 1; w <= qty; w++)
        print words[w] "@" count[words[w]]
}' inputfile
0
  awk '{ 
       BEGIN{word[""]=0;}
    {
    for (el =1 ; el <= NF ; ++el) {word[$el]++ }
    }
 END {
 for (i in word) {
        if (i !="") 
           {
              print word[i],i;
           }
                 }
 }' file.txt | sort -nr

Похожие вопросы