自打入职以来,Leader每次来我工位溜达问的最多的一句话就是「玩什么呢在?」,第二多的一句话就是「你为什么不用命令行啊?」。。。囧。。。
首先来预设一下应用场景:
现有一批60G的文本数据,每一行是一个文档,需要做分词和词频统计,即原始文本是:
1 2 3 |
我来到北京清华大学 今天天气真好 今天天气真好 |
需要将每一个文档转换成一个词列表,即:
1 2 3 |
我 来到 北京 清华大学 今天天气 真 好 今天天气 真 好 |
然后统计全局词频保存为另外一个文件,即:
1 2 3 4 5 6 7 |
我 1 来到 1 北京 1 清华大学 1 今天天气 2 真 2 好 2 |
之前在做数据预处理的时候我基本都是下意识地首选Python,分词的话肯定使用jieba,jieba本身就是Python写的,另外这么大的文本肯定要开并行,到这里我就基本不会想着用命令行了。。。
然而。。。
那只是因为我不知道有GNU parallel这种神器。。。
parallel
主要的作用就是将多个输入同时传给同一个命令并同时执行并将所有结果汇总,所以可以先用split
将数据文件切分成多个小的输入文件:
1 |
split -l 100000 input.dat newfile. |
其中的-l N
参数是指每N行切分成一个文件,newfile.
是切分后文件的前缀,切分后的文件后缀以字典序命名,如下所示:
1 2 3 4 5 6 7 8 9 10 11 |
newfile.aa newfile.ab newfile.ac . . . newfile.ba newfile.bb . . . |
然后用parallel
命令来并行分词:
1 |
ls newfile.*| parallel -j 80 -N1 --linebuffer -m python -m jieba -d' ' -q > splited_words.txt |
-j
:开启的进程数;
-N1
:每次只读取一个输入;
--linebuffer
:用来控制最后输出的时候按序输出;
-m
:在将要运行的命令包含参数的时候使用;
后面python -m jieba -d' ' -q
就是在命令行中直接调用jieba分词,最后重定向输出到splited_words.txt
文件。
分完词过后就要开始统计词频了,这里统计词频则用awk
命令来完成,首先依旧是对文件进行切分:
1 |
split -l 100000 splited_words.txt newfile_words. |
然后并行统计词频:
1 |
ls newfile_words.* | parallel -j 80 -N1 --linebuffer -q -m awk '{for(i=1;i<=NF;i++) a[$i]++} END {for)k in a) print k,a[k]}' | awk '{a[$1]+=$2} END {for(k in a) print k,a[k]}' > words_map.txt |
这里parallel
要添加一个-q
参数才能正常运行awk
,最后,因为是多个文件分别统计词频,所以还需要统计结果进行汇总,直接awk
就行啦:
1 |
awk '{a[$1]+=$2} END {for(k in a) print k,a[k]}' words_map.txt > uniq_words_map.txt |
所以最后只用了四行命令就完成了数据的快速预处理,比直接用Python代码量要少得多,更不用说跟其他语言比了,想起之前在湾区日报上也看到过说用命令行比写代码来得快的文章,学好命令行对于效率的提升还是很有帮助的,最后附上一张处理数据过程中看起来爽爽的截图: