背景

创建一个脚本来计算纯文本文件中单词的频率。该脚本执行以下步骤:

  1. 计算语料库中单词的频率。
  2. 保留在字典中发现的语料库中的每个单词。
  3. 创建频率逗号分隔的文件。

脚本在: http://pastebin.com/vazdekxs

#!/bin/bash

# Create a tally of all the words in the corpus.
#
echo Creating tally of word frequencies...
sed -e 's/ /\n/g' -e 's/[^a-zA-Z\n]//g' corpus.txt | \
  tr [:upper:] [:lower:] | \
  sort | \
  uniq -c | \
  sort -rn > frequency.txt

echo Creating corpus lexicon...
rm -f corpus-lexicon.txt

for i in $(awk '{if( $2 ) print $2}' frequency.txt); do
  grep -m 1 ^$i\$ dictionary.txt >> corpus-lexicon.txt;
done

echo Creating lexicon...
rm -f lexicon.txt

for i in $(cat corpus-lexicon.txt); do
  egrep -m 1 "^[0-9 ]* $i\$" frequency.txt | \
    awk '{print $2, $1}' | \
    tr ' ' ',' >> lexicon.txt;
done

问题

以下几行不断浏览字典以匹配单词:

for i in $(awk '{if( $2 ) print $2}' frequency.txt); do
  grep -m 1 ^$i\$ dictionary.txt >> corpus-lexicon.txt;
done

它起作用,但是它很慢,因为它正在扫描它发现的单词以删除字典中没有的任何内容。该代码通过为每个单词扫描字典来执行此任务。 (这 -m 1 当发现比赛时,参数会停止扫描。)

问题

您将如何优化脚本,以便每个单词从头到尾都不会扫描字典?大多数单词都不会在字典中。

谢谢!

有帮助吗?

解决方案

您可以使用 grep -f 在一个通过频率中搜索所有单词。txt:

awk '{print $2}' frequency.txt | grep -Fxf dictionary.txt > corpus-lexicon.txt
  • -F 搜索固定的字符串。
  • -x 仅匹配整行。
  • -f 读取dictionary.txt的搜索模式

实际上,您甚至可以将其与第二个循环结合在一起,并消除中间copus-lexicon.txt文件。可以用单个GREP替换两个循环:

grep -Fwf dictionary.txt frequency.txt | awk '{print $2 "," $1}'

注意我改变了 -x-w.

其他提示

这通常是您要以速度写的perl编写的脚本之一。但是,如果像我一样,您讨厌仅写作编程语言,那么您可以尴尬地做到这一点:

awk '
    BEGIN {
        while ((getline < "dictionary.txt") > 0)
            dict[$1] = 1
    }
    ($2 && $2 in dict) { print $2 }
' < frequency.txt > corpus-lexicon.txt

不需要 rm -f corpus-lexicon.txt 在此版本中。

使用真实的编程语言。所有应用程序启动和文件扫描都在杀死您。例如,这是我刚刚在python中进行的示例(最小化代码行):

import sys, re
words = re.findall(r'(\w+)',open(sys.argv[1]).read())
counts = {}
for word in words:
  counts[word] = counts.setdefault(word,0) + 1
open(sys.argv[2],'w').write("\n".join([w+','+str(c) for (w,c) in counts.iteritems()]))

测试我坐在AOUND(根据WC的80,000个单词)的大型文本文件的测试,这在5年历史的PowerMac上以不到第二秒(18k唯一的单词)完成。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top