R

用 Python 与 R 做英文书词频统计

Posted by Scott on July 19, 2016

背景

最近在学 MIT 的线代课,教授讲的极好,但用的是英文教材,无奈我英文太烂,有些概念看不太懂,于是便想做个词频分析,方便熟悉概念和记忆数学高频词。

首先下载 pdf 文件,链接: https://pan.baidu.com/s/1qYEgcEw 密码: 3fby。然后把需要把 pdf 转为 txt,Linux 下有个小工具 python-pdfminer,可用sudo apt-get install python-pdfminer下载。

分析

下载之后,转格式:

pdf2txt Gilbert_Strang_Introduction_to_Linear_Algebra__2009.pdf > MathLinearBook.txt

然后再下载一个 Python 词频分析工具

git clone https://github.com/Enaunimes/freeq.git

进入文件夹,把 txt 文件放进去,分析词频

cd Documents/freeq
mv ~/MathLinearBook.txt ./
./Documents/freeq/freeq.py -i MathLinearBook.txt -o MathLinearBookFreq.txt

查看下文件:

less MathLinearBookFreq.csv
10066 the
 9994 a
 5411 be
 4030 and
 2817 to
 2370 in
 2173 matrix
 1801 are
 1497 by
 1451 row
 1421 that
 1278 this
 1263 have
 1207 column
 1128 vector
 1051 for
 1037 we
  843 at

排版很舒服,但有两个问题,左列是右对齐,右列是左对齐,行首存在多个空格,不便于进一步分析;另外有大量高频词太简单了,如 the/a 等。

数据清理

考虑用 < filename | tr -s ' ' > newfile 做空格压缩,但压缩后,行首还是有空格,于是可以考虑 tr 的加强版 sed 直接删除行首多个空格,同时在首行插入列名。

sed -i 's/^ *//g' MathLinearBookFreq.csv # 第一个`/`后面是需替换内容,第二个`/`为空,表示删除,`-i` 表示替换原文件
sed -i 's/ /,/g' MathLinearBookFreq.csv # 后面的空格替换成`,`
sed -i '1i/Frequency,Word' head.csv # 插入列名

剔除熟悉词汇

那么如何去除一些太简单的高频词呢?这个时候就需要 R 语言或 Python 来做匹配了,结合 COCA 的 5000 词频表,链接: https://pan.baidu.com/s/1migyoYG 密码: vv5x。

先创建一个 WordFreq 目录存放需处理的文件,把所需文件移动到这个目录。

➜  ~ ls WordFreq 
COCA_top5000.csv                                         MathLinearBookFreq.csv
Gilbert_Strang_Introduction_to_Linear_Algebra__2009.pdf

底下是 R 代码

library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
library(readr)

导入词汇表。

df <- read_csv('~/WordFreq/COCA_top5000.csv') 
df1 <- select(df, Word) # 选择 word 这一列

df2 <- read_csv('~/WordFreq/MathLinearBookFreq.csv')
df2
#> # A tibble: 2,086 x 2
#>    Frequency   Word
#>        <int>  <chr>
#> 1      10066    the
#> 2       9994      a
#> 3       5411     be
#> 4       4030    and
#> 5       2817     to
#> 6       2370     in
#> 7       2173 matrix
#> 8       1801    are
#> 9       1497     by
#> 10      1451    row
#> # ... with 2,076 more rows

采用 dplyr 里的anti_join 函数把 df2 里面不匹配 df1 前 1000 的单词挑出来,大白话就是把你不怎么认识的词挑出来

df3 <- anti_join(df2, df1[0:1000,], by = 'Word') %>%
  arrange(desc(Frequency))
df3
#> # A tibble: 1,438 x 2
#>    Frequency     Word
#>        <int>    <chr>
#> 1       2173   matrix
#> 2       1801      are
#> 3       1451      row
#> 4       1207   column
#> 5       1128   vector
#> 6        659 solution
#> 7        589 equation
#> 8        577     zero
#> 9        547      ion
#> 10       485    pivot
#> # ... with 1,428 more rows
summary(df3)
#>    Frequency           Word          
#>  Min.   :   1.00   Length:1438       
#>  1st Qu.:   1.00   Class :character  
#>  Median :   3.00   Mode  :character  
#>  Mean   :  21.47                     
#>  3rd Qu.:   9.00                     
#>  Max.   :2173.00

但还有个问题,数学书里面有太多两位数的符号,属于无效单词,也可删除

df4 <- filter(df3, nchar(Word) > 2)
summary(df4)
#>    Frequency           Word          
#>  Min.   :   1.00   Length:1399       
#>  1st Qu.:   1.00   Class :character  
#>  Median :   3.00   Mode  :character  
#>  Mean   :  20.58                     
#>  3rd Qu.:   8.00                     
#>  Max.   :2173.00
df4
#> # A tibble: 1,399 x 2
#>    Frequency     Word
#>        <int>    <chr>
#> 1       2173   matrix
#> 2       1801      are
#> 3       1451      row
#> 4       1207   column
#> 5       1128   vector
#> 6        659 solution
#> 7        589 equation
#> 8        577     zero
#> 9        547      ion
#> 10       485    pivot
#> # ... with 1,389 more rows

大功告成,写入文件,即可

write_csv(df4, '~/WordFreq/LA_MIT_freq.csv')

写了一个 Python 版的,分析了下 Python 机器学习 这本书。