AWK语言第二版 第3章.探索性数据分析 3.1泰坦尼克号的沉没

这章也是第一版没有,第二版新增的。

3. 探索性数据分析

上一章给出了一些个人使用的小脚本,通常是特制或专用的。在本章中,我们还会展示Awk在现实中的典型使用场景:使用Awk和其他工具来非正式地探索一些真实的数据,目的是为了看看它们是什么样的。这叫做探索性数据分析(exploratory data analysis EDA),该术语由统计学先驱John Tukey 首次使用。

Tukey 发明了大量基本的数据化可视技术如箱线图(boxplot),启发了统计编程语言S(即广泛使用的R语言的前身),合作发明了快速傅里叶变换,并创造了 bit 和 software 这两个词。作为朋友和同事,作者们在上世纪80和90年代期间与 Tukey 相识于贝尔实验室,在这许多非常聪明且极富创造力的人之中,他也是相当突出而特别的。

探索性数据分析的本质,是在提出假设和给出结论之前,先玩转数据。如Tukey本人所说:“找出问题通常比发现答案更重要,探索性数据分析是态度,是灵活性,是对展示的依赖,而不是一堆技术。”

在很多情况下,这需要涉及:计数,简单的统计,用不同方式排列数据,寻找模式、共同点和奇异值,并绘制基本的图表等可视化内容。重点在于,通过做一些小而快的实验,以期能得出一些有用的启示。注意一开始不需要精雕细琢,那可以在我们对数据有了更好的认识之后再来做。

对于EDA,我们通常使用标准Unix工具如 wc、diff、 sort、uniq、grep,当然还有正则表达式。这些工具与Awk结合在一起使用效果很好,也经常结合其他语言如Python一起使用。

下面我们将遇到好几种文件格式,包括逗号或制表符分隔的值(CSV和TSV),JSON、HTML和XML。其中一些,如CSV和TSV,很容易用Awk处理,而其他类型有时用其他工具处理更好。

3.1 泰坦尼克号的沉没

第一个数据集是基于1912年4月15日的泰坦尼克号沉没事件。本书的作者之一会选择这个例子,不完全是出于巧合,当时他正经历跨大西洋的航行,在泰坦尼克沉没点的不远处经过。

汇总数据:titanic.tsv

titanic.tsv 文件内容来源于维基百科,包含了泰坦尼克号乘客和船员的汇总数据。对CSV和TSV格式来说,通常第一行会是表头,用来标识后面的数据。列之间用制表符tab分隔。

Type    Class   Total   Lived   Died
Male    First   175     57      118
Male    Second  168     14      154
Male    Third   462     75      387
Male    Crew    885     192     693
Female  First   144     140     4
Female  Second  93      80      13
Female  Third   165     76      89
Female  Crew    23      20      3
Child   First   6       5       1
Child   Second  24      24      0
Child   Third   79      27      52

许多(也许是所有的)数据集都包含错误。这里可以做个快速检查:每行要有5个域,第3个域要等于第4和第5个域的和(total = lived + died)。下面的程序打印出所有不符合条件的行:

NF != 5 || $3 != $4 + $5

如果数据格式正确而且数值也正确,只会打出一行,即表头:

Type    Class    Total    Lived    Died

一旦完成这些最简单的检查后,我们就能看看其他东西了。比如,每个类别的人有多少?

这些类别不是用数字,而是用单词标识的,如Male和Crew。幸运的是,Awk数组的下标或者说索引可以是任意的字符串,因此 gender["Male"] 和 class["Crew"] 都是合法的表达式。

允许用任意字符串做下标的数组称为关联数组;其他语言也提供相同的机制,称之为字典、映射或者哈希映射。关联数组特别地方便、灵活,因此我们将会大量地用到它。

NR > 1 { gender[$1] += $3; class[$2] += $3 }END {for (i in gender) print i, gender[i]print ""for (i in class) print i, class[i]
}

上面的程序会输出

Male 1690
Child 109
Female 425Crew 908
First 325
Third 706
Second 285

Awk的 for 语句有个特殊形式,可用于遍历关联数组的索引:

for (i in array) { statements }

会将变量 i 依次设置为数组的索引,并在执行 statements 时使用对应 i (即当前索引)的值 。数组元素的访问顺序是不确定的,你不能依赖于任何特定的顺序。【注:上面的例子用awk和gawk得到的结果顺序就不一样】

下面来看看生存率是怎么样的。社会阶层、姓名和年龄会如何影响这些乘客的生存机会?我们可以用这些汇总数据来做个简单的实验,例如计算每类人的生存率:

NR > 1 { printf("%6s  %6s  %6.1f%%\n", $1, $2, 100 * $4/$3) }

可以将awk的输出通过管道传给Unix 命令 sort -k3 -nr(按第三列倒序排序),得到结果:

 Child  Second    100.0%
Female   First     97.2%
Female    Crew     87.0%
Female  Second     86.0%Child   First     83.3%
Female   Third     46.1%Child   Third     34.2%Male   First     32.6%Male    Crew     21.7%Male   Third     16.2%Male  Second      8.3%

显然妇女和儿童的生存率高于平均水平。

注意上面的例子都将表头行当作特例进行排除(用NR > 1)。如果你要做很多实验,那么把表头从数据集中删去,也许会比每次写代码去忽略首行要简单。

乘客数据:passengers.csv

passengers.csv 文件较大,它包含了乘客的详细信息,但没有包含船员信息。原始文件是把一个广泛使用的机器学习数据集和另一个维基百科的列表合并起来得到的。文件共有11列,其中包含了乘客们的故乡、所分配的救生艇、票价等:

"row.names","pclass","survived","name","age","embarked","home.dest","room","ticket","boat","sex"
...
"11","1st",0,"Astor, Colonel John Jacob",47,"Cherbourg","New York, NY","","17754 L224 10s 6d","(124)","male"
...

这文件有多大?可以使用Unix的 wc 命令来统计行数、单词数和字符数:

$ wc passengers.csv1314    6794  112466 passengers.csv

或者使用我们在第一章写的两行Awk程序来统计:

    { nc += length($0) + 1; nw += NF }
END { print NR, nw, nc, FILENAME }

得到的结果是一样的(当然两者在输出格式上稍微有区别,比如空格数量不一样)

passengers.csv 文件是 CSV格式(comma-separated values)。尽管CSV格式没有严格的定义,但通常都有这样的规则:如果某一域的内容包含逗号或者双引号,则整个域都要用双引号包起来。任何域都可以用双引号包起来,不管它的内容是否包含逗号或者双引号。空的域表示为""(两个双引号),而域内容里的双引号用两个双引号表示,例如 """,""" (前后共6个双引号)表示 ","。CSV文件的输入域可以包含换行符。更多细节参见附录 A.5.2。

这种格式大致也是Ms Excel和其他电子表格程序如Apple Numbers和Google Sheets所采用的。这种格式还是Python的Panda库和R语言默认的data frame格式。

2023年以来的Awk版本,如果加入命令行参数 --csv ,则会将输入行按上面的格式进行拆分。如果只是简单的用 FS=, 来设置域分隔符,则无法做到这一点,这种做法只能处理最简单的CSV格式,即不包含双引号的。如果你使用旧版本的Awk,也许最简单的做法是用其他工具(如Excel或Python的CSV模块),把数据转换成其他格式。

另一个有用的替代格式是TSV(制表符分隔的值)。它和CSV思想是一样的,但更简单:域之间用单个tab制表符分隔,没有双引号机制,因此域就不能包含嵌套的tab或换行。这种格式用Awk处理很简单,只要通过 FS="\t" 将域分隔符设置为tab,或者在命令行参数中带 -F"\t" 效果也是一样的。

另外提一下,在处理文件内容之前验证一下它的格式是否正确,会比较明智。例如,校验所有的记录行是否都有相同的域数量,可以使用

awk '{print NF}' file | sort | uniq -c | sort -nr

其中第一个sort 排序命令能够将所有相同的行都聚在一起;之后的 uniq -c 命令会将连续的相同行合并成一行,给出相同行的计数以及该行的内容;最后的 sort -nr 把结果按数值倒序排列,因此最大值输出在最前面。

对passengers.csv文件,用上面的脚本,再额外加上 --csv 选项来对CSV格式进行正确处理,得到:

1314 11

可见每条记录的域数量都相同,这是合法数据的必要条件,当然不是充分条件。如果发现某些行的域数量不一样,接着就可以使用Awk把它们找出来,比如用 NF != 11 条件来过滤。

如果使用老版本即不支持CSV的Awk,用 -FS, 来处理文件,会得到:

624 12
517 13
155 1415 153 11

可见基本上所有的记录里都包含了内嵌的逗号。

顺带一提,生成CSV是很容易的。下面这个函数 to_csv ,通过将双引号替换成两个双引号,并在得到的结果两边加上双引号,就能把字符串转换成符合CSV格式要求的字符串。这个函数也可以添加到第二章所述的个人库里面。

# to_csv - convert s to proper "..."function to_csv(s) {gsub(/"/, "\"\"", s)return "\"" s "\""
}

(注意在字符串中引号使用反斜杠进行转义处理)

我们可以在循环中使用这个函数,并在数组的元素之间插入逗号,来将一个数组(关联数组或索引数组)转换成一条格式合法的CSV记录。参见如下两个函数 rec_to_csv 和 arr_to_csv:

# rec_to_csv - convert a record to csvfunction rec_to_csv(   s, i) {for (i = 1; i < NF; i++)s = s to_csv($i) ","s = s to_csv($NF)return s
}# arr_to_csv - convert an indexed array to csvfunction arr_to_csv(arr,   s, i, n) {n = length(arr)for (i = 1; i <= n; i++)s = s to_csv(arr[i]) ","return substr(s, 1, length(s)-1) # remove trailing comma
}

下面的程序从原始文件中选择五个属性(类别、是否生还、姓名、年龄、性别)输出,域之间用制表符tab分隔:

NR > 1 { OFS="\t"; print $2, $3, $4, $5, $11 }

输出结果如下:

1st 0   Allison, Miss Helen Loraine  2  female
1st 0   Allison, Mr Hudson Joshua Creighton 30  male
1st 0   Allison, Mrs Hudson J.C. (Bessie Waldo Daniels) 25  female
1st 1   Allison, Master Hudson Trevor   0.9167 male

年龄字段大部分是整数,但也有部分是小数,如上面的最后一行。Helen Allison是两岁, Master Hudson Allison看起来是11个月大,而且是他们家族的唯一幸存者。(从其他来源我们得知,Allison家的司机George Swane,18岁,也遇难了,但女佣和厨师都得救了)

泰坦尼克上有多少婴儿?执行命令

$4 < 1

并用tab作为域分隔符,可以得到8行:

1st 1   Allison, Master Hudson Trevor    0.9167 male
2nd 1   Caldwell, Master Alden Gates     0.8333 male
2nd 1   Richards, Master George Sidney   0.8333 male
3rd 1   Aks, Master Philip   0.8333 male
3rd 0   Danbom, Master Gilbert Sigvard Emanuel   0.3333 male
3rd 1   Dean, Miss Elizabeth Gladys (Millvena)   0.1667 female
3rd 0   Peacock, Master Alfred Edward   0.5833  male
3rd 0   Thomas, Master Assad Alexander  0.4167  male

练习3-1、修改单词计数程序,使之能为每个输入文件产生一个单独的计数结果,就像Unix命令wc一样。

更进一步的检查

另一类要探索的问题,是两个数据源的一致性。两个数据都来自维基百科,但它并不总是完全精确的数据源。假如我们检查一些最基本的,比如有多少乘客在 passengers 文件中:

$ awk 'END {print NR}' passengers.csv
1314

这里还包含了表头行,所以是1313个乘客。而我们还可以从汇总文件第三个域中统计非船员的人数:

$ awk '!/Crew/ { s += $3 }; END { print s }' titanic.tsv
1316

差了3个人,肯定哪里错了。

再来个例子,算算有多少儿童?

awk --csv '$5 <= 12' passengers.csv

结果有100行,和汇总文件titanic.tsv里得到的109人对不上。

也许儿童的定义是不超过13岁?但结果是105。用14岁试试?结果是112。通过计算被称为“Master”的乘客数量,我们可以猜测用的是哪个数字:

awk --csv '/Master/ {print $5}' passengers.csv | sort -n

里面最大的年龄是13岁,尽管不能确定,但也许这个猜测最接近实际。

上面两种情况下,数字都应该是相同的,但实际上却不同,这说明数据还是不太靠谱。可见在探索数据时,你要总是准备好应付数据在形式和内容上的错误和不一致。在开始下结论之前,要做大量的工作来保证你已经识别并处理了潜在的问题。

在本节中,我们已尽力展示如何用简单的计算来帮助识别这样的问题。如果你收集一些工具来做公共的操作,如分离域,按类分组,打印最常见和最少见的条目,等等,你就更好地进行这些检查操作。

练习3-2、根据你自己的需要和品味,为自己写一些工具。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/114450.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

3D双目跟踪瞳孔识别

人眼数据集通常用于眼部相关的计算机视觉、眼动追踪、瞳孔检测、情感识别以及生物特征识别等领域的研究和开发。以下是一些常见的人眼数据集&#xff1a; BioID Face Database: 这个数据库包含1,521张近距离的人脸图像&#xff0c;其中包括瞳孔位置的标记。它通常用于瞳孔检测和…

Linux 中断

CPU自动完成 GIC驱动 Linux内核 用户编写的中断服务程序 request_irq() free_irq() typedef irqreturn_t (*irq_handler_t)(int, void *) enable_irq() disable_irq() local_irq_enable() local_irq_restore() local_irq_disable() local_irq_save() 上半部//顶半…

effective c++学习笔记(后四章)

六 继承与面向对象设计 红色字 \color{FF0000}{红色字} 红色字 32 确定你的public继承塑模出 is-a关系 如果你令class D (“Derived”)以public形式继承class B (“Base”)&#xff0c;你便是告诉C编译器&#xff08;以及你的代码读者&#xff09;说&#xff0c;每一个类型为…

Origami Studio for Mac:塑造未来,掌握原型设计之巅

在当今高度竞争的设计领域&#xff0c;原型设计的重要性不言而喻。它不仅是沟通想法&#xff0c;也是测试和改进设计的关键环节。而现在&#xff0c;一款强大的原型设计工具——Origami Studio for Mac&#xff0c;正在席卷设计界&#xff0c;以其独特的功能和卓越的性能&#…

shell变量

shell变量之学习笔记 Shell变量概念1 shell变量分类&#xff1a;2 变量的赋值3 变量赋值格式&#xff1a;4 变量命名方式5 变量声明6 变量引用7 变量清除8 变量只读9 内部参数变量10 位置参数变量11 退出和返回状态12 命令替换13 read命令14 字符串长度与截取15 字符串替换16 变…

Spring Security—Servlet 应用架构

目录 一、Filter&#xff08;过滤器&#xff09;回顾 二、DelegatingFilterProxy 三、FilterChainProxy 四、SecurityFilterChain 五、Security Filter 六、打印出 Security Filter 七、添加自定义 Filter 到 Filter Chain 八、处理 Security 异常 九、保存认证之间的…

利用TreeMap来解决P3029 [USACO11NOV] Cow Lineup S

P3029 [USACO11NOV] Cow Lineup S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 好了&#xff0c;我们首先要统计奶牛的种类数量n&#xff0c;好与接下来我们记录一个范围内的奶牛的数量作比较&#xff0c;一旦我们统计范围内的奶牛的数量m达到我们刚开始记录的奶牛的数量n我…

20231018刷题记录

P1878 舞蹈课 堆。 对于“舞蹈技术差”这一变量&#xff0c;可以想到用优先队列维护实现 O ( log ⁡ n ) O(\log n) O(logn) 级别的复杂度。 对于整个舞蹈队伍的删除操作&#xff0c;可以用双向链表维护&#xff0c;比较经典的应用是开车旅行。这个东西首先比 STL 方便&#x…

C语言【文件】

目录 概念 文件名 文件的打开和关闭 fopen fclose 输入输出函数 fputc fgetc fputs fgets fprintf fscanf fwrite fread 三种流 scanf和sprintf 结构体转化 ​编辑 文件的随机读写 fseek ftell rewind 文本文件和二进制文件 文件读取结束的判定 文件缓冲…

C++标准模板(STL)- 类型支持 (运行时类型识别,type_info )

运行时类型识别 定义于头文件 <typeinfo> 含有某个类型的信息&#xff0c;由实现生成。​​这是 typeid 运算符所返回的类。 std::type_info 定义于头文件 <typeinfo> class type_info; 类 type_info 保有一个类型的实现指定信息&#xff0c;包括类型的名称和…

【论文解读】Parameter-Efficient Transfer Learning for NLP

一. 介绍 1.1 为什么要引入Adapter 在存在许多下游任务的情况下&#xff0c;微调的参数效率很低:每个任务都需要一个全新的模型。作为替代方案&#xff0c;我们建议使用适配器模块进行传输。 1.2 论文目标 目标是建立一个在所有这些方面都表现良好的系统&#xff0c;但不需…

docker图形胡界面管理工具--Portainer可视化面板安装

1.安装运行Portainer docker run -d -p 8088:9000 \ > --restartalways -v /var/run/docker.sock:/var/run/docker.sock --privilegedtrue portainer/portainer--restartalways&#xff1a;Docker启动后容器自动启动 -p&#xff1a;端口映射 -v&#xff1a;路径映射2.通过…

写一个简单的解释器(2) 构建标记流

确定标记类型 分为几个大类&#xff1a; 用户符号&#xff08;类型/标识符/数字/字符串…)关键字 (流程控制和定义符)括号 &#xff08;这里暂时认为 [] 属于括号&#xff09;分号 上述四类标记基本囊括了 vc \texttt{vc} vc 中的所有最小单元的类型&#xff0c;但是因为构…

【C++】哈希应用——海量数据面试题

哈希应用——海量数据面试题 一、位图应用1、给定100亿个整数&#xff0c;设计算法找到只出现一次的整数&#xff1f;2、给两个文件&#xff0c;分别有100亿个整数&#xff0c;我们只有1G内存&#xff0c;如何找到两个文件交集&#xff1f;&#xff08;1&#xff09;用一个位图…

JAVA基础(JAVA SE)学习笔记(七)面向对象编程(进阶)

前言 1. 学习视频&#xff1a; 尚硅谷Java零基础全套视频教程(宋红康2023版&#xff0c;java入门自学必备)_哔哩哔哩_bilibili 2023最新Java学习路线 - 哔哩哔哩 第二阶段&#xff1a;Java面向对象编程 6.面向对象编程&#xff08;基础&#xff09; 7.面向对象编程&…

Ubuntu下 u2net tensorrt模型部署

TensorRT系列之 Windows10下yolov8 tensorrt模型加速部署 TensorRT系列之 Linux下 yolov8 tensorrt模型加速部署 TensorRT系列之 Linux下 yolov7 tensorrt模型加速部署 TensorRT系列之 Linux下 yolov6 tensorrt模型加速部署 TensorRT系列之 Linux下 yolov5 tensorrt模型加速…

nginx部署vue项目(访问路径加前缀)

nginx部署vue项目(访问路径加前缀) nginx部署vue项目&#xff0c;访问路径加前缀分为两部分&#xff1a; &#xff08;1&#xff09;修改vue项目&#xff1b; &#xff08;2&#xff09;修改nginx配置&#xff1b; vue项目修改 需注意&#xff0c;我这是vue-cli3配置&#x…

某验四代滑块验证码逆向分析

逆向目标 目标&#xff1a;某验四代滑块验证码&#xff0c;w 参数逆向主页&#xff1a;aHR0cHM6Ly9ndDQuZ2VldGVzdC5jb20v加密算法&#xff1a;RSA、AES 通讯流程 验证码流程分析 进入网页后&#xff0c;打开开发者人员工具进行抓包&#xff0c;点击滑动拼图验证&#xff0c…

Vue3语法-双向绑定

点击加入精英计划可以加入 点击名字可以删除 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title><!-- vue.js --><script src"https://unpkg.com/vue3/dist/vue.glob…

微软正式发布开源应用平台 Radius平台

“ 10 月 18 日&#xff0c;微软 Azure 孵化团队正式发布开源应用平台 Radius&#xff0c;该平台将应用程序置于每个开发阶段的中心&#xff0c;重新定义应用程序的构建、管理与理解方式。” 简单的概括就是&#xff0c;它和Kubernetes不一样&#xff0c;Radius将应用程序放在每…