信息社会的今天,数据科学越来越重要。在数据科学中,算法为本,工具为重。除了Mathlab,Scilab,Jupyter,IPython notebook和NumPy,R语言,Julia语言等等,其实还有一个值得重视的工具(集),那就是Linux Shell。本文将为大家介绍数据科学中常用Linux shell工具。善用这些工具可以极大提高数据处理的效率。
常用Linux同学一定非常熟悉“|” 符号,这就是shell管道。管道的作用是将一个工具(进程)的输出传递给另一个工具(进程)处理。这样可以将各个shell工具套成一个处理链,进行一栈式流水处理。
'>'是输出重定向符号,可用于重定向输出,可用于重定向标准输出到文件。比如,对数据文件(,分开)的第一列进行统计,统计每个其内容以及出现的次数。
cat example.txt | awk -F’,’ ‘{print $1}’ | sort | uniq -c > tongji.txt
‘<’ 符号是一个输入重定向符号,可以将文件的内容重定向到标准入。
grep xxx < example.txt
上面个说了一栈式流水处理,但是我们在流式处理的同时,有希望将某个输出保留下。这就要用到tee命令,和其字面意思 “三通”一样,tee命令是让将流信息传递个管道的同时还可以保存到文件。
./cc.sh | tee cc.log
在数据科学中’tee’实际上并不能做任何分析,但如果调试复杂的shell管道为啥不能正常工,用tee非常有用。举一个上面的例子,并在管道的每个阶段之间放置对“tee”命令的引用:
cat example.txt | awk -F’,’ ‘{print $1}’ | sort | uniq -c > tongji.txt
运行此命令时会生成4个日志文件,这些日志文件记录整个管道流水过程中每个阶段的输出情况。如果希望能够返回并检查发生罕见或复杂错误的壳管,这会很有用。
Grep是shell文本三剑客之一。可用于从文件中搜索匹配关键字的行。支持很多控制标志和选项,可以有选择性地要从文件或流中提取的感兴趣的内容。Grep默认 “面向行”处理,当找到匹配的文本时,grep将打印该行上的所有文本,可以使用“-o”标志仅打印匹配的部分线。
grep很有用,它在大量文件中搜索特定文本非常高效。比如要从巨大(几十G)的Web服务器日志中过滤对特定网页的访问,或者在代码库中搜索特定关键字的实例;
Grep对于临时数据科学任务非常有用,它允许快速地从数据集中过滤出想要的信息。源数据很可能包含大量与问题无关的信息。如果数据存储在文本文件中的各个行上,如果能想到一个非常精确的搜索规则来过滤掉它们,则可以使用grep仅提取想要使用的行。例如,如果有以下example.csv文件,每一行都包含一条销售记录:
grep xxx < example.txt
要筛选出包含文本球鞋的销售记录:
grep 球鞋 example.csv
对于复杂的搜索可以使用正则表达式。 例如要过滤掉所有以’BN’或’MN’开头且后跟至少3个数字的型号:
grep -o “(BN|MN)([0-9]){3}” example.csv
结果为:
MN009
MN089
BN009
sed 是shell文本三剑客之一,一个用于执行搜索和替换操作的工具。例如,可以使用一条很简单命令:
./cc.sh | tee cc.log
将当前目录中所有文件中的cc一词的所有实例替换为CC。
Sed中可以使用正则表达式来执行复杂的匹配和替换。正则表达式替换还支持反向引用,允许匹配任意模式,然后以某种方式仅更改匹配文本的一部分。 例如,如下sed 命令将在任何给定的行上查找两个带引号的字符串,然后交换它们的位置而不改变文本的任何其他部分,并替换for为in,同时将引号更改为括号:
echo ‘There are many useful “Linux shell” tools for “DATA Science”.’ | sed -E ‘s/"(["]+)"(["]+)"([^"]+)"/(\3)\2(\1)/;s/for/in/’
结果如下:
There are many useful (DATA Science) tools in (Linux shell).
在数据科学中sed的最大用例是规范化数据格式用于进行数据清洗和规范。例如,有一个文本文件“data.txt”,其中包含数千个用双引号括起来的数字:
age,value
“33”,“5943”
“32”,“543”
“34”,“93”
“39”,“5943”
“36”,“9943”
“38”,“8943”
可以通过以下sed命令运行进行处理:
cat data.csv | sed ‘s/"//g’
结果就都变成规范的数字:
age,value
33,5943
32,543
34,93
39,5943
36,9943
38,8943
如果遇到过一些简单的格式错误导致导入失败或无法正确处理的数据集问题,可以尝试用sed进行数据预处理。
awk也shell文本三剑客之一,可以进行更高级的搜索和替换操作,这些操作可能需要通用计算。
Awk基本上算是一种通用编程语言,可以轻松处理格式化的文本行。与sed和grep的功能有些重叠,但awk的功能要强大得多。
假设温度值数据文件“temps.csv”,其数据单位混合使用可摄氏度或华氏度,为了统一需要需要将华氏温度转化为摄氏温度:
cat temps.csv
温度,单位
26.1,C
78.1,F
23.1,C
25.7,C
76.3,F
77.3,F
24.2,C
79.3,F
27.9,C
75.1,F
25.9,C
79.0,F
可以使用一个简单的awk命令来完成该操作:
cat temps.csv | awk -F’,’ ‘{if($2==“F”)print (($1-32)*5/9)",C";else print $1","$2}’
结果为:
将所有温度值都统一为摄氏温度。
和其名称字面意思一样,sort主要用于排序。Sort并不会直接使用。但是如果要筛选出其他数据任务中统计最大/最小的时候,就需要先对其进行排序,然后取第一个或最后一个。需要top 10,top X也需要先对其进行排序。
现有一个文本文件example.txt,我们用sort进行排序:
cat example.csv | tail -n +2 | tee after_tail.log | awk -F’,’ ‘{print $1}’ | tee after_awk.log | sort | tee after_sort.log | uniq -c | tee after_uniq.log
首先默认不加任何参数情况下排序:
sort example.txt
结果是:
默认排序是按字母表顺序而不是数字顺序进行的,因此数字可能不是期望的顺序。添加“-n”参数进行数字排序:
sort -n example.txt
结果:
现在数字按正确顺序排列。另一个常见的需求是反序排序,可以使用“-r”参数来实现:
sort -r example.txt
结果:
数据科学中,sort一般结合comm、uniq 等配合使用,先用sort对输入数据进行排序。sort另一个用例是用-R进行随机排序,这样每次结果都不一样,只科学实验中随机抽取样表很有用。
tsort是一种可用于拓扑排序的工具。拓扑排序是解决可能每天都在不知不觉中遇到的许多现实问题的方法 一个非常著名的例子是制定一个乐器学习计划来完成许多任务,而这些任务必须在前一任务完成后才能开始。在日常应用中,这样的依赖条件需求是常见的。假设有任务的列表example.tk:
吃饭 睡觉
睡觉 打豆豆
吃饭 打豆豆
随便 打豆豆
在上面的文件中,每一行由两个单词组成。用tsort命令处理文件时,两个词是先后出现的顺序,第一个词在第二次前面。处理完所有行后,tsort将整体按照所有顺序输出。
tsort example.tk
结果如下:
吃饭
随便
睡觉
打豆豆
可以在 sort -R 标志来获得文件中行的随机排序。如果对依赖项列表进行重复的随机排序并将其通过管道传输到tsort,会注意到结果始终相同,即使“sort -R”的输出每次都不同:
sort -R example.tk | tsort
即使每次重新排列任务相互依赖的实际顺序也不会改变。
comm 是一种基于输入文件中的文本行计算集合运算结果的工具(并集、交集和补集)。
假设有两个包含电子邮件地址数据,其中一个列表mail.txt的文件,其中包含注册电子邮件地址:
另是sale.txt文件,其中包含购买人的电子邮件地址:
现在想知道
1) 哪些注册邮箱并购买产品的用户?(交集)
2) 哪些用户注册了邮箱,但没有购买?
3) 哪些用户购买了但没有注册邮件?
使用comm命令,就可以轻松回答所有这三个问题。
首先是问题1:
名称, 型号,价格, 税
球鞋, MN009, 49.99, 1.11
球鞋, MTG09, 139.99, 4.11
T恤, MN089, 28.99, 1.44
短裤, N09, 39.99, 1.11
球鞋, KN09, 49.99, 1.11
皮鞋, BN009, 449.22, 4.31
球鞋, dN099, 149.99, 1.22
香蕉, GG009, 4.99, 1.11
结果:
问题2:
grep 球鞋 example.csv
产生以下结果:
最后,是问题3:
grep -o “(BN|MN)([0-9]){3}” example.csv
结果为:
MN009
MN089
BN009
产生以下结果:
注意comm 命令要求其内容是排序后的。如果文件未排序就会提示错误:
comm: file 1 is not in sorted order
comm: file 2 is not in sorted order
可以在结合输入重定向和sort首先处理,然后在用comm:
comm -12 <(sort email.txt) <(sort sale.txt)
uniq命令是对数据进行去重(并计数)的工具,uniq和sort通常一起使用。
如果你想删除重复的行并只输出唯一的行,uniq会这样做。要知道每个项目重复次数,用uniq -c。
假设一份销售数据文件sales.csv:
sed -i ‘s/cc/CC/g’ *
并且想要销售数据中,总共卖出去那些产品。可以使用awk获取产品并将结果通过管道传输到sort和uniq
awk -F’,’ ‘{print $1}’ sales.csv | sort | uniq
T恤
球鞋
短裤
袜子
要知道每个产品卖出去的件数,也可以
echo ‘There are many useful “Linux shell” tools for “DATA Science”.’ | sed -E ‘s/"(["]+)"(["]+)"([^"]+)"/(\3)\2(\1)/;s/for/in/’
可以使用-d标志,获取多次出现的项目列表。
wc命令是一个工具,获得文本文件的单词数和行数。如果想要快速知道有多行数据时候wc非常有用。Wc通常结合uniq使用,统计项目的计数。
在数据科学中wc使用的很频繁,比如统计列表的次数,比如要获得email文件中的邮件数(行数):
age,value
“33”,“5943”
“32”,“543”
“34”,“93”
“39”,“5943”
“36”,“9943”
“38”,“8943”
结果中减去一个(如果文件中包含csv标头)就是邮件数。
如果要统计多个文件,支持使用通配符:
cat data.csv | sed ‘s/"//g’
计算一段文本或文件中的字符数通常很有用。甚至可以将文本粘贴到echo语句中(使用 -n 来避免换行符计数):
echo -n "There are so many cool tools in linux shell " | wc -c
结果:
44
head命令打印出文件的前几行(或字节)。如果想查看一个巨大文件的一小部分,或者如果想从分析的另一部分计算top 3结果之类的结果,用head 非常好用,通常结合sort使用(xxx|sort|uniq|sort-nr|head -n 3)
对于我们的产品销售文件sales.csv:
想知道:“从最受欢迎到最不受欢迎的前3名畅销产品是什么?”。可以使用:
awk -F’,’ ‘{print $1}’ sales.csv | sort | uniq -c | sort -nr | head -n 3
上述脚本中,先用awk取出销售文件中的第一列即销售产品列表,然后对其排序(必须),然后uniq去重并计数,然后根据uniq计数数字按照逆袭排序,然后取出前三项,即Top 3.
结果:
3 袜子
2 短裤
2 球鞋
Tail和 head相反,取出结尾的n行数据。更常用的用例是tail -f动态输出最新的变化的内容。以及用于清理数据文件中一些行,比如一般csv文件的第一行为标头行在数据处理中需要去除,可以用tail -n +2 就可以。
tr命令是一种可以删除或替换单个字符或字符“集”的工具。比如去除windows换行符:
echo -en “Hello\r” | tr -d “\r” | xxd
0000000: 4865 6c6c 6f Hello
还可以使用 ‘tr’ 命令进行其他特殊情况更正。 例如,有时可能会遇到使用空字符分隔而不是换行符的二进制数据。则可以使用tr命令用换行符替换文件中的所有空字符:
echo -en “\0” | tr \0 \
| xxd
注意,上面命令中的双 ‘’ 字符是必需的,因为tr期望“\0”表示空字符,但 ''本身在shell中需要进行转义。上面的命令显示了通过管道传输到 'xxd’中的结果。
Tr在数据科学主要用数据处理和清洗,进行一个格式转化和特殊情况数据修复。
cat是shell最常用的一个工具,用于显示文件的内容。当需要将多个文件拼接在一起,或者想将文件输出到标准输出时,cat 命令非常有用。
在执行数据科学任务时,cat常用于串联多个文件的数据。比如对于多个具有类似格式内容的csv文件时,可以使用cat聚合到一起。
cat a.csv b.csv c.csv | awk -F’ ’ ‘{print $1}’ | sort | uniq
当然最常用的用例是
cat abc.txt | command
find’命令可以使用许多不同的选项来搜索文件,它还能够对每个文件执行命令。
find 命令对于在给定许多不同选项(文件/目录类型、文件大小、文件权限等)的情况下搜索文件很有用,但它最有用的功能之一,是其-exec选项,它允许对找到文件,批量执行命令进行处理。
说明如何使用 find 命令列出当前目录中和当前目录下的所有文件:
find . -type f -exec cat {} ; | wc -l
带有 find 命令的“-exec”选项的语法可能是最难记住的语法之一,因为它不是在其他地方重复的常见模式。 下面是如何使用 find 命令将当前目录中和当前目录下的每个文件中的单词 ‘dog’ 替换为单词 ‘cat’ 的另一个示例:
find . -type f -exec sed -i ‘s/dog/cat/g’ {} ;
可以通过更改 ‘.’ 在当前目录以外的另一个特定目录上运行与上述命令类似的命令。 请小心使用find 的“-exec”执行,尤其是以 root 身份运行时。如果不小心对“/”目录运行了错误的命令,可能会造成很大的损害。
最终会遇到的一个常见问题与混合不同的 Unicode 编码有关。有时候如果使用 grep 搜索文件时,得不到预期结果,但是cat时候明明有数据的,这是可以用zzd用十六进制形式查看文件:
xxd sometext.txt
给出以下输出:
00000000: fffe 4800 6500 6c00 6c00 6f00 2000 5700 …H.e.l.l.o. .W.
00000010: 6f00 7200 6c00 6400 2100 0a00 o.r.l.d.!..
可以发现文件“somefile.txt”以UTF-16 编码,但终端(可能)默认为UTF-8。 将UTF-16编码文本中的字符打印到UTF-8编码终端并没有显示出明显的问题。
但是用grep搜索Hello时,键入的字符将被解释为当前在终端环境中设置的字符编码(可能设置为 UTF-8). 因此,搜索字符串在这些 ASCII 字符之后不包含额外的空字节,因此搜索失败。如果你想搜索UTF-16字符,可以使用:
grep -aP “H\x00e\x00l\x00l\x00o\x00” * sometext.txt
‘a’ 标志是打开二进制文件搜索所必需的,因为UTF-16中的空字符会导致文件被grep解释为二进制文件。P标志指定grep模式应该被解释为Perl正则表达式,这样’\x’转义被解释。
或者,如果知道给定文件是UTF-16,可以先将其转换为UTF-8格式,则可以使用以下命令执行此操作:
iconv -f UTF-16 -t UTF-8 sometext.txt > sometext-utf-8.txt
现在在处理此文件时无需采取任何特殊步骤,编码与当前终端编码兼容:
00000000: 4865 6c6c 6f20 576f 726c 6421 0a Hello World!.
正如本文中提到的(非全部),有大量的Linux shell工具命令对于快速解决数据科学问题非常有用。本文只为每个命令展示一些用例,抛砖引玉,希望大家探索很多的shell工具来解决数据问题。