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 函数。
来源
在本文中,我们计算了《钦定本雅各王圣经》的单词频率。