用命令行做数据科学(上)

212 阅读4分钟

今天介绍一本非常不错的书,英文名是Data Science at the Command Line。书中介绍了如何用命令行来获取、处理和展示数据,效率远远高于自己开发Python脚本来实现这些功能,所以非常值得学习。

1. Linux命令行介绍

Linux系统有许多命令行工具,这些工具可以完成非常强大的功能。如grep命令可以用来在文本中搜索特定的字符串,wc可以计算文本的行数,sort可以对文本进行排序等。命令行工具运行的时候是一个进程,每个进程都有三个标准的输入输出流,分别是标准输入*stdin, 标准输出stdout, 以及错误输出stderr*。当在终端中运行rev命令时,rev将接收用户在键盘上输入的字符串,进行反序后输出到屏幕,其原理如下图所示。

\

Figure 1.1: Every tool has three standard streams: standard input (stdin), standard output (stdout), and standard error (stderr)

我们还可以通过管道符号|将多个命令串联起来执行,前面一个命令的标准输出结果会传给后一个命令的标准输入进行进一步的处理。下面的命令下载一个文本文件,并通过grep搜索出其中含有CHAPTER的行:

$ curl -s "https://www.gutenberg.org/files/11/11-0.txt" | grep " CHAPTER"
 CHAPTER I.     Down the Rabbit-Hole
 CHAPTER II.    The Pool of Tears
 CHAPTER III.   A Caucus-Race and a Long Tale
 CHAPTER IV.    The Rabbit Sends in a Little Bill
 CHAPTER V.     Advice from a Caterpillar
 CHAPTER VI.    Pig and Pepper
 CHAPTER VII.   A Mad Tea-Party
 CHAPTER VIII.  The Queens Croquet-Ground
 CHAPTER IX.    The Mock Turtles Story
 CHAPTER X.     The Lobster Quadrille
 CHAPTER XI.    Who Stole the Tarts?
 CHAPTER XII.   Alices Evidence

这个命令行的工作原理如下图所示,curl下载文件的内容通过标准输出成为grep的输入,grep执行查找后输出到屏幕上:\

Figure 1.2: The output from a tool can be piped to another tool

注意,如果curl执行出错,错误信息并不会传给grep,而是显示在屏幕上。

我们还可以将命令行的输出进行重定向,比如重定向到文件中。下面的命令将执行结果重定向到chapter.txt文件中:

$ curl "https://www.gutenberg.org/files/11/11-0.txt" | grep " CHAPTER" > chapter
s.txt
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  170k  100  170k    0     0   197k      0 --:--:-- --:--:-- --:--:--  198k
 
$ cat chapters.txt
 CHAPTER I.     Down the Rabbit-Hole
 CHAPTER II.    The Pool of Tears
 CHAPTER III.   A Caucus-Race and a Long Tale
 CHAPTER IV.    The Rabbit Sends in a Little Bill
 CHAPTER V.     Advice from a Caterpillar
 CHAPTER VI.    Pig and Pepper
 CHAPTER VII.   A Mad Tea-Party
 CHAPTER VIII.  The Queens Croquet-Ground
 CHAPTER IX.    The Mock Turtles Story
 CHAPTER X.     The Lobster Quadrille
 CHAPTER XI.    Who Stole the Tarts?
 CHAPTER XII.   Alices Evidence

下图是上面这个命令行的工作原理:

Figure 1.3: The output from a tool can be redirected to a file

在Linux系统中有一个特殊的文件 /dev/null,我们可以通过将错误输出重定向到该文件的方式禁止命令在屏幕上显示错误信息,如下所示:

$ cat movies.txt 404.txt
Matrix
Star Wars
Home Alone
Indiana Jones
Back to the Future
/usr/bin/cat: 404.txt: No such file or directory
$ cat movies.txt 404.txt 2> /dev/null ➊
Matrix
Star Wars
Home Alone
Indiana Jones
Back to the Future

其中数字2代表的是标准错误输出stderr。\

2. 开发环境准备

该书的作者提供了一个Docker镜像用于开发者学习使用。Docker的安装可以参考网上的教程,这里不再赘述。安装完Docker后,首先下载作者的镜像:

$ docker pull datasciencetoolbox/dsatcl2e

运行镜像:

$ docker run --rm -it datasciencetoolbox/dsatcl2e

Docker容器相当于一个沙箱,我们没有办法直接访问里面的文件,容器内也无法访问外部的文件,但是我们可以将本地的一个目录映射到容器内部,这样就可以在容器内部访问本地的文件。通过在运行容器的时候指定-v参数即可实现该功能,下面的命令将当前执行命令的目录映射到docker容器到根目录/data下面:

$ docker run --rm -it -v "$(pwd)":/data datasciencetoolbox/dsatcl2e

这样我们在容器内部就可以在/data目录下对外部的数据进行操作。

作者还提供了用于训练的测试数据,下载地址是:

www.datascienceatthecommandline.com/2e/data.zip

3. 获取数据

我们可以直接从网上下载数据,然后根据上一节的方法映在docker容器中进行处理,也可以在docker中直接从网上下载数据。Linux系统中有一个非常强大的工具curl,支持超过20多种网络协议,可以用来执行各种网络请求。

下载并保存文件

$ curl -s "https://en.wikipedia.org/wiki/List_of_windmills_in_Friesland" -O

或者

$ curl -s "https://en.wikipedia.org/wiki/List_of_windmills_in_Friesland" > friesland.html

-s的作用是抑制输出错误信息,-O将文件保存到本地。\

Http请求重定向

$ curl -s "https://youtu.be/dQw4w9WgXcQ"

-L参数用于指示curl处理需要重定向到网址。

$ curl -sI "https://youtu.be/dQw4w9WgXcQ" | trim

-I参数指示curl只返回http请求到header数据。

文件解压缩

$ tar -xzf logs.tar.gz ➊ 

如果只想看看压缩文件里有哪些内容,使用-t参数\

$ tar -tzf logs.tar.gz | trim

-C参数指定解压缩到特定目录下\

$ mkdir logs
 
$ tar -xzf logs.tar.gz -C logs

作者提供了一个简易的命令unpack,

$ unpack logs.tar.gz

Excel处理

CSVKit提供了一系列工具,如in2csv、csvgrep、csvlook等来处理csv文件。

in2csv这个命令可以将Excel文件转为csv文件

$ in2csv top2000.xlsx | tee top2000.csv | trim

要查看csv文件的内容,可以用下面的工具\

$ csvlook tmnt-with-header.csv
│ name         │ nickname      │ mask_color │ weapon           │
├──────────────┼───────────────┼────────────┼──────────────────┤
│ Leonardo     │ Leo           │ blue       │ two ninjakens    │
│ Raphael      │ Raph          │ red        │ pair of sai      │
│ Michelangelo │ Mikey or Mike │ orange     │ pair of nunchaku │
│ Donatello    │ Donnie or Don │ purple     │ staff            │
 

这个工具将在终端中以格式化的方式显示结果。

搜索csv文件中特定的字符串:

$ csvgrep top2000.csv --columns ARTIEST --regex '^Queen$' | csvlook -I 
 NR.   ARTIEST  TITEL                            JAAR 
├──────┼─────────┼─────────────────────────────────┼──────┤
 2     Queen    Bohemian Rhapsody                1975 
 11    Queen    Love Of My Life                  1975 
 46    Queen    Innuendo                         1991 
 55    Queen    Don't Stop Me Now                1979 
 70    Queen    Somebody To Love                 1976 
 85    Queen    Who Wants To Live Forever        1986 
 89    Queen    The Show Must Go On              1991 
 131   Queen    Killer Queen                     1974 
 with 24 more lines

--regex指定一个正则表达式。

数据库

在命令行中处理数据库等工具有很多,其中sql2csv,也是CSVkit中的一个工具,可以处理包括Oracle、MySQL等各种数据库,

$ sql2csv --db 'sqlite:///r-datasets.db' \
> --query 'SELECT row_names AS car, mpg FROM mtcars ORDER BY mpg' | csvlook
│ car                 │  mpg │
├─────────────────────┼──────┤
│ Cadillac Fleetwood  │ 10.4 │
│ Lincoln Continental │ 10.4 │
│ Camaro Z28          │ 13.3 │
│ Duster 36014.3 │
│ Chrysler Imperial   │ 14.7 │
│ Maserati Bora       │ 15.0 │
│ Merc 450SLC         │ 15.2 │
│ AMC Javelin         │ 15.2 │
… with 24 more lines

Web API数据

这里也是用curl请求api数据

$ curl -s "https://anapioficeandfire.com/api/characters/583" | jq '.'
{
"url": "https://anapioficeandfire.com/api/characters/583",
"name": "Jon Snow",
"gender": "Male",
"culture": "Northmen",
"born": "In 283 AC",
"died": "", ➊
"titles": [
"Lord Commander of the Night's Watch"
  ],

curl也支持需要认证的http请求,可以在header中传入token等认证参数,这里将apikey保存到文件中,传给curl进行认证请求:

$ curl -s "http://newsapi.org/v2/everything?q=linux&apiKey=$(< /data/.secret/new
sapi.org_apikey)" |
> jq '.' | trim 30
{
  "status": "ok",
  "totalResults": 9088,
  "articles": [
    {

对数据流进行采样

$ curl -s "https://stream.wikimedia.org/v2/stream/recentchange" |
> sample -s 10 > wikimedia-stream-sample

4. 创建复杂的脚本

各种命令组合在一起可以完成非常复杂的任务,如下

$ curl -sL "https://www.gutenberg.org/files/11/11-0.txt" | ➊
> tr '[:upper:]' '[:lower:]' | ➋
> grep -oE "[a-z']{2,}" | ➌
> sort | ➍
> uniq -c | ➎
> sort -nr | ➏
> head -n 10 ➐
   1839 the
    942 and
    811 to
    638 of
    610 it
    553 she
    486 you
    462 said
    435 in
    403 alice

➊ curl下载一本电子书.
➋ tr将所有的文本转为小写.
➌ grep提取出所有的单词,每个单词放到单独的一行中.
➍ sort按字母顺序排序.
➎ uniq删除重复的词,并计算每个词出现的频率.
➏ sort按出现频率降序排序
➐ head保留前10个结果

上面这些词在英文中被称为stopwords,它们出现的频率本身就很高,为了更好的统计单词,最好过滤掉这些词不予统计。先通过下面的命令找出所有的stopwords:

$ curl -sL "https://raw.githubusercontent.com/stopwords-iso/stopwords-en/master/
stopwords-en.txt" |
> sort | tee stopwords | trim 20
10
39
a
able
ableabout
about
above
abroad
abst
accordance
according
accordingly
across
act
actually
ad
added
adj
adopted
ae
… with 1278 more lines

再使用下面的命令,统计除stopwords之外的单词:

$ curl -sL "https://www.gutenberg.org/files/11/11-0.txt" |
> tr '[:upper:]' '[:lower:]' |
> grep -oE "[a-z']{2,}" |
> sort |
> grep -Fvwf stopwords | ➊
> uniq -c |
> sort -nr |
> head -n 10
    403 alice
     98 gutenberg
     88 project
     76 queen
     71 time
     63 king
     60 turtle
     57 mock
     56 hatter
     55 gryphon

我们可以将上面的命令封装到一个脚本文件中,如下所示

$ bat top-words-5.sh
───────┬────────────────────────────────────────────────────────────────────────
       │ File: top-words-5.sh
───────┼────────────────────────────────────────────────────────────────────────
   1   │ #!/usr/bin/env bash
   2   │
   3   │ NUM_WORDS="${1:-10}"
   4   │
   5   │ tr '[:upper:]' '[:lower:]' |
   6   │ grep -oE "[a-z']{2,}" |
   7   │ sort |
   8   │ grep -Fvwf stopwords |
   9   │ uniq -c |
  10   │ sort -nr |
  11   │ head -n "${NUM_WORDS}"
───────┴────────────────────────────────────────────────────────────────────────

NUM_WORDS是从命令行传给脚本的参数,  $1表示命令行的第一个参数,如果没有传参数取默认值“10”。

$ curl -sL "https://www.gutenberg.org/files/11/11-0.txt" > alice.txt
 
$ < alice.txt ./top-words-5.sh 20
    403 alice
     98 gutenberg
     88 project
     76 queen
     71 time

\

原文 mp.weixin.qq.com/s?__biz=MzI…