Go词频教程展示了如何在Golang中计算词频。
$ go version go version go1.18.1 linux/amd64
我们使用Go版本1.18。
我们的示例仅适用于拉丁词,并且专门针对分析圣经。
$ wget https://raw.githubusercontent.com/janbodnar/data/main/the-king-james-bible.txt
我们使用钦定版圣经。
为了将文本切割成单词,我们使用Go的strings.FieldsFunc
和正则表达式。
Go词频示例I
FieldsFunc
函数在每次运行满足提供函数的Unicodecode点时拆分字符串,并返回一个切片数组。
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 } } }
我们计算KingJames圣经中单词的出现频率。
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词频例子二
在第二个示例中,我们使用正则表达式将文本分成单词。
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
映射中构建了一片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]) }
我们打印前十个最常见的单词。
围棋词频例子三
在下一个示例中,我们还使用正则表达式。
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
函数。
在本教程中,我们计算了钦定版圣经中的词频。
列出所有Go教程。