标题党一回, 现如今到处都是各种”大数据”, 本文分析对象也就是首批积分落户的6000多条数据而已, 显然不能算什么大数据.
概述
本文是 Shell 的一次综合应用, 充分利用 Shell 中的管道, 结合常用的 Shell 命令, 如 sort, uniq, cut, grep, awk, sed
等等命令对之前官方公布的首批北京积分落户同学进行分析.
目前政府官方数据公示期已过, 已经不能从官方网站下载相应的公示数据了, 后文用到的数据来源于某CSDN博客. 印象中, 我记得当初该官网的这6000多条数据也是一次性就能wget下来的(后端估计没做限制, 可能稍微调整下接口的分页参数之类不需要严格按照各种分页多次下载).
问题描述
拿到的是json数据, 格式化之后的json数据主题结构如下所示, rows为数组, 数组中元素所代表的object即描述了获得北京户口的同学的各种属性, 例如分数, 排名, 身份证号(后四位打码了), 还有公司等等信息. 为了方便大家练习对数据进行试验, 我将数据附在这里, 如果有侵权, 请联系我删除.
"rows": [ |
拿到这个文件, 比如希望你用最快的方法获得以下信息, 你将会怎么做?
- 获取取得户口名额最多的top10公司
- 获取取得户口名额的人中姓氏最多的
- 获取户口名字中叫啥名最流行
- 获取年龄分布
- 获取取得户口的同学户籍地top10
- 生肖/星座/生日…
当然, 方法有很多, 比如熟悉各种编程语言的, 例如 python, php, java
等等写个简单的脚本程序, 也能比较快获取答案. 或者把相应的数据提取出来, 放到 excel 中也可以.
如果你对 shell 很熟悉, 那真的是分分钟, 哦, 应该是秒秒种就能获取答案. 就算用Shell来实现, 不同的人可能也有不同的写法, 后面我就列举其中的一种来解决这些问题. 本文不对 Shell 具体每个命令做过多的解释, 不熟悉的同学 可以直接 man $cmd
或者 $cmd --help
等等查看, 之前我也写过一篇名叫 Shell 助力开发效率提升 的文章, 算是给常用的命令的常用参数做了一个解释和示例, 有兴趣的同学可以前往查阅.
问题解答
获取取得户口名额最多的top10公司
看看想通过积分落户, 最好是进哪些公司, 哈哈.
“unit”: “北京利德华福电气技术有限公司”
先通过 grep
得到包含公司名字的一行, 然后通过 “:” 分割 cut
取第2列得到公司名字, 对结果进行sort
排序进行去重uniq
统计得到重复次数, 次时结果为重复次数 公司名
, 再对第一列-k 1
重复数字进行按照数字排序逆序-nr
即 sort -nr -k 1
, 最后取结果的前10行 head -n 10
.
➜ 积分落户 > grep 'unit' jifenluohu.json| cut -f2 -d: | sort | uniq -c | sort -nr -k 1 | head -n 10 |
获取取得户口名额的人中姓氏最多的
看看想通过积分落户, 最好是姓啥, 哈哈.
“name”: “杨效丰”,
套路跟之前差不多的, 我这边就不特别指出了. 下面shell实际上是取到这行后, 将真正表示名字之前的所有字符都删除, 就只剩下名字开头了, 取行首第一个字符cut -c 1
即得到姓, 再按照之前的套路就能拿到了.
其实用什么sed
替换冗余的字符都是多余的, 因为json的格式都是良好的, 可以直接通过 cut -c ?
取姓这个字符即可. 也不用挨个去数到底是第几个字符, 直接 copy出来, 然后 echo -n $paste | wc -c
就能数到第几个字符了.
看结果还是姓 “张, 王” 之类的最有戏. :)
# 或者 grep '"name":' jifenluohu.json| sed 's|"name": "||g' | sed 's|[[:space:]]||g' | cut -c 1 | sort | uniq -c | sort -nr -k 1 | head -n 10 |
获取户口名字中叫啥名最流行
套路差不多, 不做过多解释了.
➜ 积分落户 > grep '"name":' jifenluohu.json| sed 's|"name": "||g' | sed 's|[[:space:]]||g' | cut -c 2-4 | sort | uniq -c | sort -nr -k 1 | head -n 10 |
作为码农, 必须得养成对自己得到结果进行自测的习惯, 所以如果对自己的结果不够自信, 可以正向去计算一下最终的结果.
例如可以简单grep
一下进行验证, 叫 “海涛” 的是不是19个.
➜ 积分落户 > grep '海涛' jifenluohu.json | wc -l |
获取年龄分布
思路是截取身份证中号码中代表出生年的4位数, 然后拿当前年份2019减出生年得到年龄, 后面的套路又一样了.
bc
一个简单的计算器程序, 了解下?
➜ shell-train > echo "3+2-5/5" | bc |
#思路1: `cut -c 9-12` 获取出生年, 拼接表达式 `2019-出生年` 得到年龄. |
awk
是个好东西, 多练练.
# 拿到出生年后, 直接通过 awk 计算结果输出 |
获取取得户口的同学户籍地top10
有时候, 我们在写Shell的时候, 为了debug方便, 可能会将一些中间结果缓存到文件中, 后续以该文件为基础进行后续的计算.
比如先拿到top10的身份证中代表的户籍地的四位编码, 这里需要借助另外的一个表示身份证户籍地的编码来进行对应. 借此机会解释下 join
这个命令.
# 身份证前4位为例, 拿到户籍地 |
其实, join
就类似sql
中的 ...inner join ...on ...
, -t
分隔符, 默认为空格或tab
.
# 未排序, 所以没有将所有的导出(join需要排序) |
一定需要将结果输出到文件, 然后再进行吗? 其实也不一定. 管道的方式 |
可以将上一个命令的输出结果作为下一个命令的输入, 可以通过 <(command)
的方式, 将command
的输出作为一个文件输入.
# 需要排序 |
举个例子paste
用来将两个文件按列合并在一起,
➜ shell-train > cat paste.f1 |
以上用paste
将两个文件合并在一起了, 实际上通过 <(cmd)
的方式, 可以不借助外部文件也能做到. 方法如下:
➜ shell-train > paste <(echo "hello, i am \nworld, you are") <(echo "tanglei, wechat is: tangleithu\n?, hahaha") |
其他
这里就不重复多讲了, 剩下的问题, 要不你动手试试? 比如看看生日最多的? 再试试获取 生肖/星座 最多的top10.
有任何疑问, 欢迎留言交流参与交流讨论.