Go 单词频率
最后修改时间 2024 年 4 月 11 日
在本文中,我们将展示如何在 Golang 中计算单词频率。
我们的示例仅适用于拉丁语单词,并且专门针对分析《圣经》。
$ wget https://raw.githubusercontent.com/janbodnar/data/main/the-king-james-bible.txt
我们使用《英王钦定本圣经》。
为了将文本分割成单词,我们使用 Go 的 strings.FieldsFunc
和正则表达式。
Go 单词频率示例 I
FieldsFunc
函数在满足所提供函数的每个 Unicode 代码点运行时分割字符串,并返回一个切片数组。
read_freq.go
package main import ( "fmt" "io/ioutil" "log" "sort" "strings" ) func main() { fileName := "the-king-james-bible.txt" bs, err := ioutil.ReadFile(fileName) if err != nil { log.Fatal(err) } text := string(bs) fields := strings.FieldsFunc(text, func(r rune) bool { return !('a' <= r && r <= 'z' || 'A' <= r && r <= 'Z' || r == '\'') }) wordsCount := make(map[string]int) for _, field := range fields { wordsCount[field]++ } keys := make([]string, 0, len(wordsCount)) for key := range wordsCount { keys = append(keys, key) } sort.Slice(keys, func(i, j int) bool { return wordsCount[keys[i]] > wordsCount[keys[j]] }) for idx, key := range keys { fmt.Printf("%s %d\n", key, wordsCount[key]) if idx == 10 { break } } }
我们统计《英王钦定本圣经》中单词的频率。
fields := strings.FieldsFunc(text, func(r rune) bool { return !('a' <= r && r <= 'z' || 'A' <= r && r <= 'Z' || r == '\'') })
FieldsFunc
按非字母字符和撇号分割文本。这也将忽略所有诗句编号。
wordsCount := make(map[string]int) for _, field := range fields { wordsCount[field]++ }
每个单词及其频率存储在 wordsCount
映射中。
keys := make([]string, 0, len(wordsCount)) for key := range wordsCount { keys = append(keys, key) } sort.Slice(keys, func(i, j int) bool { return wordsCount[keys[i]] > wordsCount[keys[j]] })
为了按频率对单词进行排序,我们创建了一个新的 keys
切片。我们将所有单词放入其中,并按它们的频率值对它们进行排序。
for idx, key := range keys { fmt.Printf("%s %d\n", key, wordsCount[key]) if idx == 10 { break } }
我们打印圣经中出现频率最高的十个词。
$ go run word_freq.go the 62103 and 38848 of 34478 to 13400 And 12846 that 12576 in 12331 shall 9760 he 9665 unto 8942 I 8854
Go 单词频率示例 II
在第二个示例中,我们使用正则表达式将文本划分为单词。
word_freq2.go
package main import ( "fmt" "io/ioutil" "log" "regexp" "sort" ) type WordFreq struct { word string freq int } func (p WordFreq) String() string { return fmt.Sprintf("%s %d", p.word, p.freq) } func main() { fileName := "the-king-james-bible.txt" reg := regexp.MustCompile("[a-zA-Z']+") bs, err := ioutil.ReadFile(fileName) if err != nil { log.Fatal(err) } text := string(bs) matches := reg.FindAllString(text, -1) words := make(map[string]int) for _, match := range matches { words[match]++ } var wordFreqs []WordFreq for k, v := range words { wordFreqs = append(wordFreqs, WordFreq{k, v}) } sort.Slice(wordFreqs, func(i, j int) bool { return wordFreqs[i].freq > wordFreqs[j].freq }) for i := 0; i < 10; i++ { fmt.Println(wordFreqs[i]) } }
我们将单词及其频率存储在 WordFreq
结构中。
reg := regexp.MustCompile("[a-zA-Z']+")
在我们的正则表达式中,一个或多个字母字符或一个撇号构成一个单词。
matches := reg.FindAllString(text, -1)
FindAllString
函数返回一个由表达式所有连续匹配组成的切片。
words := make(map[string]int) for _, match := range matches { words[match]++ }
我们遍历匹配项并在文件中计算它们的频率。单词及其出现次数存储在 words
map 中。
var wordFreqs []WordFreq for k, v := range words { wordFreqs = append(wordFreqs, WordFreq{k, v}) }
我们从 words
map 构建一个 WordFreq
结构的切片。
sort.Slice(wordFreqs, func(i, j int) bool { return wordFreqs[i].freq > wordFreqs[j].freq })
我们按 freq
字段对 wordFreqs
切片进行排序。
for i := 0; i < 10; i++ { fmt.Println(wordFreqs[i]) }
我们打印出最常见的十个单词。
Go 单词频率示例 III
在下一个示例中,我们也使用正则表达式。
word_freq3.go
package main import ( "fmt" "io/ioutil" "log" "regexp" "sort" ) type WordFreq struct { word string freq int } func (p WordFreq) String() string { return fmt.Sprintf("%s %d", p.word, p.freq) } type byFreq []WordFreq func (a byFreq) Len() int { return len(a) } func (a byFreq) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a byFreq) Less(i, j int) bool { return a[i].freq < a[j].freq } func main() { fileName := "the-king-james-bible.txt" bs, err := ioutil.ReadFile(fileName) if err != nil { log.Fatal(err) } text := string(bs) re := regexp.MustCompile("[a-zA-Z']+") matches := re.FindAllString(text, -1) words := make(map[string]int) for _, match := range matches { words[match]++ } var wordFreqs []WordFreq for k, v := range words { wordFreqs = append(wordFreqs, WordFreq{k, v}) } sort.Sort(sort.Reverse(byFreq(wordFreqs))) for i := 0; i < 10; i++ { fmt.Printf("%v\n", wordFreqs[i]) } }
此示例还实现了自定义排序接口。
type byFreq []WordFreq func (a byFreq) Len() int { return len(a) } func (a byFreq) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a byFreq) Less(i, j int) bool { return a[i].freq < a[j].freq }
我们基于 freq
字段为 []WordFreq
实现 sort.Interface
。
sort.Sort(sort.Reverse(byFreq(wordFreqs)))
为了以降序对 WordFreq
结构进行排序,我们使用 sort.Reverse
函数。
来源
在本文中,我们计算了《钦定本雅各王圣经》的单词频率。