命令行数据科学工具笔记
《Data Science at the Command Line》阅读笔记。
用命令行工具来提升效率,还有这种操作.jpg
说,对于命令行/终端操作界面可能嗤之以鼻。但不可否认的是使用命令行的效率是大于图形界面的。 无意间看到了这本书,觉得里面的一些命令行操作非常实用,也是之前没有接触过的。故记录书中的一些
本书在线阅读的网站是https://www.datascienceatthecommandline.com/ 示例和GitHub地址是https://github.com/jeroenjanssens/data-science-at-the-command-line
如何执行命令行工具呢?在终端下输入相应的命令就行了,比如
常见的命令行工具可以分成5种:
重定向输入输出,如
和文件打交道,常用的命令是移动/剪切
在命令行中寻求帮助,对于每个命令行工具,一般是有相应的说明文档的,比如
Bash常用快捷键,熟悉了的话能够提高不少效率。
基于位置: 生成一个10行的数据用于演示。
基于模式: 使用
基于随机: 使用
逐个文件循环:
前言
对于习惯了Windows图形化操作界面的人来通用的技巧,在很多Linux下面都是同样适用的。 对于涉及到具体的问题,可以诸如Python解决的,就跳过了。这些命令不必烂熟于行,但至少说,对于命令行/终端操作界面可能嗤之以鼻。但不可否认的是使用命令行的效率是大于图形界面的。 无意间看到了这本书,觉得里面的一些命令行操作非常实用,也是之前没有接触过的。故记录书中的一些
本书在线阅读的网站是https://www.datascienceatthecommandline.com/ 示例和GitHub地址是https://github.com/jeroenjanssens/data-science-at-the-command-line
入门起步
首先你需要一定的GNU/Linux知识,至少会使用Linux系统。那么命令行工具的环境大致可以分为四层:命令(Command Line
)->终端(Terminal)
->Shell
->操作系统(Operating System)
。Shell是解释你输入命令的,一般我们在Linux发行版中使用的Shell是bash,当然也有其它的比如大名鼎鼎的zsh。如何执行命令行工具呢?在终端下输入相应的命令就行了,比如
$ pwd
就会给出当前的地址。常见的命令行工具可以分成5种:
- 二进制可执行文件,一般是由其它编译而成的
- Shell自带命令,比如
cd
和help
- 可解释脚本,如Python脚本
- Shell函数,Shell是自带了一些函数的如
seq
,fac
- 命令别名(alias),你可以把一些很长的命令用别名的方式来简化。
$ seq 100 | grep 3 | wc -l
seq 100
的作用是输出1-100的数,那么grep就在输出中找出含有3
的项,之后wc -l
就是数grep
之后输出的行数,那么这里有19个。重定向输入输出,如
$ seq 10 > output.txt
就可以把命令行的输出保存到文件中,这在许多调试中是非常有用的。
下面的命令中,echo的-n
是不换行,>>
是指在文件后接着写(append的方式)$ echo -n "Hello" > hello-world.txt
$ echo " World" >> hello-world.txt
接下来看看怎么读取文件,一个常用的命令是cat
,如$ cat hello-world.txt | wc -w
,其中-w
参数是数单词数(words),这条的结果应该是2,因为"Hello World"有两个单词。
当然还有其它的方法,这句和上面的输出是一样的$ < hello-world.txt wc -w
,只不过它将hello-word.txt文件直接加载到了wc的输入流里面。或者直接使用wc
的参数$ wc -w hello-world.txt
,但此时输出会将文件名附在单词数后面。和文件打交道,常用的命令是移动/剪切
mv
,复制cp
,删除rm
。下面整理了最常用的一些命令。
$ mv hello.txt ~/book/ch02/data/
将文件移动到文件夹中;
$ cd data
切换目录,$ mv hello.txt bye.txt
重命名;
$ rm bye.txt
删除文件,$ rm -r book/ch02/data/old
删除文件夹;
$ cp server.log server.log.bak
复制文件,$ mkdir logs
新建文件夹在命令行中寻求帮助,对于每个命令行工具,一般是有相应的说明文档的,比如
man cat
就可以查看cat
工具的说明。下面列举了常见的三种查看帮助文档的方式。
$ man cat | head -n 20
使用man
命令查看帮助前20行;
$ help cd | head -n 20
对于一些工具使用help
也是一样的。
$ jq --help
大部分工具都有--help
这个参数,也一样可以查看帮助Bash常用快捷键,熟悉了的话能够提高不少效率。
获取数据
解压
在Linux中,我们最常见到的压缩文件后缀名是.tar.gz
,.zip
和.rar
文件,对应的解压缩命令是tar
,unzip
和unrar
,注意在使用他们之前要确保已经正确安装了这些工具。
比如,$ tar -xzvf data/logs.tar.gz
,注意命令的参数是-xzvf
,分别对应解压archive、gzip解压、verbose输出、指定file。
书中提供了实用的Bash脚本来解压不同类型的文件,附上地址。转换Excel文件
很多情况下,使用Excel保存的数据文件会存放在一个xlsx文件中,对于命令行工具来说非常不友好,通用一点的数据格式是CSV格式。 这时候in2csv
命令就能派上用场了。需要先安装一下sudo pip install csvkit
。
之后就可以使用命令$ in2csv data/imdb-250.xlsx > data/imdb-250.csv
将xlsx文件转换成csv文件了。
使用$ in2csv imdb-250.xlsx | head | cut -c1-80
可以查看,但是输出的是原始的逗号分隔文件,非常不友好。为了使显示效果更好,可以使用csvlook
的管道。
如in2csv data/imdb-250.xlsx | head | csvcut -c Title,Year,Rating | csvlook
的效果会好很多。
另一种处理的方式就是使用Libre Office这样的的软件打开,再进行转换。但这样非常不方便,而且你在用服务器的时候使不可能装一个Office套件的。查询关系数据库
关系型数据库常见的有MySQL,PostgreSQL和SQLite等。使用命令行工具sql2csv
可以更方便的使用CSV处理SQL数据库。
如使用$ sql2csv --db 'sqlite:///data/iris.db' --query 'SELECT * FROM iris '\> 'WHERE sepal_length > 7.5'
进行query查询操作。从网上下载数据
使用最多的是cURL
工具。
$ curl -s http://www.gutenberg.org/cache/epub/76/pg76.txt | head -n 10
,参数-s
表示silent模式。
$ curl http://www.gutenberg.org/cache/epub/76/pg76.txt > data/finn.txt
将curl下载的内容到文件中,此时不能用-s
模式。
$ curl -s http://www.gutenberg.org/cache/epub/76/pg76.txt -o data/finn.txt
使用-o
参数指定输出文件,此时可以使用-s
。
$ curl -u username:password ftp://host/file
下载FTP上的文件
$ curl -L j.mp/locatbbar
当网址是诸如http://bit.ly/*
的自动跳转等短网址时,加上-L
参数就可以下载跳转之后的网页内容。通过API请求数据
很多时候我们需要通过一些在线服务提供的API来获取数据。比如我们需要知道某地的天气时,就需要通过一些天气服务提供商提供的网络接口来获取数据,通常返回的数据格式时json形式的。使用最基础的curl就能实现,如$ curl -s http://api.randomuser.me | jq '.'
当我们需要更高级的操作时则需要其它工具,这在后续会涉及到。创建可复用的命令行工具
其实就是将命令写进一个脚本文件。这在我们需要重复连续执行繁琐的命令的时候会非常有用。当然这里只能介绍一些基本的脚本编写,更复杂的需要阅读Shell脚本编写的相关书籍。将单行指令转换为Shell脚本
通常要经历下面几个步骤:- 将单行指令复制粘贴到一个文件中
- 给文件添加执行权限
- 定义一个shebang行(如#!/bin/sh)
- 去除固定输入部分
- 添加参数
- 可选的拓展你的路径
复制单行命令到文件
有一个技巧是可以通过!!
来代替上一条执行了的命令。
一般来说我们会将Bash脚本命令放到.sh
文件中,表明是shell脚本。我们就可以通过$ bash book/ch04/top-words-1.sh
这样的命令来执行Shell脚本了。添加权限
绝大多数情况下,我们实用vim
或者nano
编辑器创建的.sh
文件是没法直接执行的。因为我们还需要给它赋予可执行权限。那么这时候就要用到更改权限的命令chmod
。在终端中执行$ chmod u+x top-words-2.sh
,其中u
指定是用户(也就是你),+x
代表增加执行权限。这样你就可以在终端中直接执行./top-words-2.sh
来运行这个脚本了。
通过$ ls -l top-words-2.sh
来查看文件具体信息,我们可以看到权限部分由原来的-rw-rw-r--
变到了-rwxrw-r--
,增加了x,执行权限。定义shebang
在bash脚本的第一行,我们需要加入#!/usr/bin/env bash
来告诉终端是用bash来执行这个脚本。
如果你添加的是#!/usr/bin/python
,那么就是用python来执行。去除固定输入
把bash脚本中的固定输入部分删除,这样我们就可以通过终端把我们需要的输入直接给脚本,而无须每次都改动脚本。$ cat data/finn.txt | top-words-4.sh
,通过管道把数据给shell脚本。参数化
下面的脚本内容定义了一个变量NUM_WORDS
,在使用这个变量的时候需要在前面加$符号,这个变量的内容是$1
代表着脚本第一个输入参数,比如./xx.sh 1
里的1。#!/usr/bin/env bash
NUM_WORDS="$1"
tr '[:upper:]' '[:lower:]' | grep -oE '\w+' | sort |
uniq -c | sort -nr | head -n $NUM_WORDS
拓展你的PATH
很多情况下,在不同的文件夹中,你也想使用你之前编写好的脚本,这时候把脚本所在路径添加到系统PATH中就能够使你在任何地方访问到。$ echo $PATH | fold
想要长期的改变系统的环境变量的话,就需要修改.bashrc
或.profile
文件了。使用Python创建命令行工具
迁移脚本
上面的脚本,可以同样使用Python来实现,下面代码给出了实现。#!/usr/bin/env python
import re
import sys
from collections import Counter
num_words = int(sys.argv[1])
text = sys.stdin.read().lower()
words = re.split('\W+', text)
cnt = Counter(words)
for word, count in cnt.most_common(num_words):
print "%7d %s" % (count, word)
这时候我们就可以通过Python脚本来执行我们所需的功能,将数据流输入到脚本并附上参数5。$ < data/76.txt top-words.py 5
使用标准输入来处理流数据
当输入数据流是类似命令行形式而非文件时,你就不可能一次性全部处理掉,故需要一行一行处理。#!/usr/bin/env python
from sys import stdin, stdout
while True:
line = stdin.readline()
if not line:
break
stdout.write("%d\n" % int(line)**2)
stdout.flush()
清洗数据
对普通文本操作
过滤行
主要用到的命令行工具是sed
和awk
基于位置: 生成一个10行的数据用于演示。
$ seq -f "Line %g" 10 | tee data/lines
打印前三行:$ < lines head -n 3
;$ < lines sed -n '1,3p'
;$ < lines awk 'NR<=3'
打印末三行:$ < lines tail -n 3
删除前三行:$ < lines tail -n +4
;$ < lines sed '1,3d'
;$ < lines sed -n '1,3!p'
删除末三行:$ < lines head -n -3
打印4-6行:$ < lines sed -n '4,6p'
;$ < lines awk '(NR>=4)&&(NR<=6)'
;$ < lines head -n 6 | tail -n 3
打印奇数行:$ < lines sed -n '1~2p'
;$ < lines awk 'NR%2'
打印偶数行:$ < lines sed -n '0~2p'
;$ < lines awk '(NR+1)%2'
基于模式: 使用
grep
和正则表达式
$ grep -E '^CHAPTER (.*)\. The' alice.txt
,在alice.txt中找出所有以"The"开头的章节基于随机: 使用
sample
工具创建数据集的子集
$ seq 1000 | sample -r 1% | jq -c '{line: .}'
可以指定sample的延时,避免数据一下子太快打印出来而产生错误,这在调试你的脚本时非常有用。
$ seq 10000 | sample -r 1% -d 1000 -s 5 | jq -c '{line: .}'
提取值
使用grep
的输出到cut
工具中
$ grep -i chapter alice.txt | cut -d' ' -f3-
替换与删除
使用tr
工具
$ echo 'hello world!' | tr ' ' '_'
,把空格替换成了下划线
$ echo 'hello world!' | tr -d -c '[a-z]'
,删除不是a-z的字符
tr
也可以用来转换大小写
$ echo 'hello world!' | tr '[a-z]' '[A-Z]'
,将小写转换成大写
$ echo 'hello world!' | tr '[:lower:]' '[:upper:]'
,与上面效果相同操作CSV
使用了三种工具:body
、header
和cols
操作HTML和JSON
使用了curl
、scrape
、xml2json
、jq
、json2csv
管理你的数据工作流
原书使用了Drake工具。因为不太通用,故跳过。探索数据
用了R语言中大名鼎鼎的ggplot2来进行数据可视化。 在Python中可以使用matplotlib或plotly等可视化工具。并行管道
普通循环
这个还是挺有用的。 使用bc
来计算数学表达式。$ echo "4^2" | bc
$ for i in {0..100..2}
> do
> echo "$i^2" | bc
> done | tail
逐行循环:$ while read line
> do
> echo "Sending invitation to ${line}."
> done < data/emails.txt
也可以从标准输入流(即你的控制台输入)中获取数据
$ while read i; do echo "You typed: $i."; done < /dev/stdin
逐个文件循环:
$ for filename in *.csv
> do
> echo "Processing ${filename}."
> done
还可以使用find
来更灵活的寻找文件
$ find data -name '*.csv' -exec echo "Processing {}" \;
GNU Parallel
非常好用的一个工具,可以让循环变得简单,并且易于管理。$ seq 5 | parallel "echo {}^2 | bc"
Comments
Post a Comment