Bash玩转脚本3之几个指令有趣的筛选京东评价
今天在工作中遇到了一个筛选和去重问题,饶有兴致祭出Mac(为了跟公司同步,写Android一直用Win~),三两个指令搞定了去重复筛选问题,回到家中意犹未尽,决定总结一下这些年使用bash做数据筛选和去重的经验。
传送门:
一、数据
找数据是个头疼的问题,不过在百度过程中缺找到了一个蛮好的网站,推荐给大家http://www.datatang.com/,我从中下载了一个京东手机评价的数据,随便找了一组数据,命名为data.txt,作为本次玩耍的原始数据。
文本数据一共有多少行?
那就 wc -l
一下看看。(wc是一个统计的指令,“|“是管道,简单理解就是对前面的结果继续操作)
可以看到一共有346957行,内容还是蛮多的,我们截取文本部分内容,可以看到内容的结构如图所示:
基本上所有的数据的格式都是:
- No 编号
- uName 名字
- uLevel 等级
- uAddress 地址
- star 星级
- commentDate 时间
…
- 购买日期 时间
ok,了解了结构那现在就可以对这份数据进行我们想要的任何操作了~
二、让我想想可能需要的数据
<1> 一共有多少个评价呢?
这里可以通过使用grep 指令对某个结构内一定会出现的关键字进行抓取,然后使用wc指令统计数量,我抓取的关键字是编号——”No”。
grep "No" data.txt | wc -l
可以看到一共是有32065个评价~
<2>那32065个评价中有多少5星好评呢?
1)如果格式足够规整的话,我可以像<1>操作那样筛选,只不过关键字变成了 “star 5” ,我们可以看看结果。
grep "star 5" data.txt | wc -l
注:细心的朋友可能看出了实际的指令有点点的不同,那是因为star和5间有个tab,我使用\t表示了~
2)当然,我们还有更好的方法,首先我们可以使用awk把数据进行一次格式化,然后再进行抓取和想要的操作
cat data.txt | grep "star" | awk -F "[\t]" ‘{print $2}‘
稍微解释一下,我们通过grep抓取出所有的包含star的行,然后把这些行,使用\t分隔符进行分割(awk的作用)成两列,第一列全是star,第二列则是星数,而我们把星数那一列全部print出来(这里的head -n 30只是为了方便看,只取了头30行)
万万没想到中间竟然有一条干扰数据star186102(原来有个货的用户名包含star!):
那怎么办?其实很容易,使用grep -v 剔除这一条就好了~(-v表示排除再外),完整指令如下:
cat data.txt | grep "star" | awk -F "[\t]" ‘{print $2}‘ | grep -v "star186102" | grep "5" | wc -l
结果和刚才的一样~都是25274!
<3>所有评价的平均星数是多少?
答案是还是使用awk,这个工具太强大了,我们对<2>中的awk指令做小小的修改:
cat data.txt | grep "star" | awk -F "[\t]" ‘{sum = sum + $2} END {print sum/32065}‘
我们在awk里面加入了重要的东西,那就是语句,做了一个累加的操作,可以想象到这个东西是多么的强大。(有兴趣的请自行百度awk吧!)
可以看出,>,< 4.64的评分还是蛮高的!
<4>那么谁的评论最认真呢?
怎么评判认真呢?最这里我简单的把评论最长就认为最认真~
1)首先我们要进行抓取,我选择了抓取“心得“这个关键字
cat data.txt | grep "心 得"
这里可以看到有很多很多的心得,我就不列举了。
2)使用awk对数据进行整理
cat data.txt | grep "心 得" | awk -F "心 得\t" ‘{print $2}‘
这次分割符我使用的是”心 得\t”,注意这里没有中括号,因为中括号的意思是里面的分隔符支持正则表达式,所有有没有都行。
3)我们修改一下awk的输出,使之打印出每一句评价的长度,然后这用sort进行排序
完整指令如下:
cat data.txt | grep "心 得" | awk -F "心 得\t" ‘{print length($2)"---"$2}‘ | sort -n -r | head -n 1
让我们欣赏一下最佳评价:
。。。
欣赏完了,我们解释一下,awk中的print length($2)打印出了每条心得的长度,然后加了一个- - -作为分割,因此格式就变成了:内容长度- - -内容;然后我们使用sort进行排序,-r代表倒序,-n代表按照数字排序,这样我们就得到了一个从大到小的以数字开头的列表;最后使用head -n 1取出最前的一条!
<5>这货是谁?
竟然“评价“的那么认真,那么就请出来亮个相吧!
我们通过grep语句,抓取关键字附近的内容来看看,这里我们选择的关键字就是“我发现作者在做班主任工作的时候也有很多的无奈“这一句话。
grep -A 5 -B 10 "我发现作者在做班主任工作的时候也有很多的无奈" data.txt
- A:代表向后,后面接行数
- B:代表向前,后面接行数
这里我抓取了关键行前10行和后5行,看到了uName,名字叫j***1的朋友~看来他就是这个评论的作者了。
<6>喜欢用京东的人群地域分布是怎么样?
通过观察可以看到,uAddress就是注册时候填写到地域信息。虽然有部分人是没有写的,不过也不妨碍我们从技术到角度来实现这个问题。
我想到了用uniq,因为可以对数据进行去重,-c选项能够列出去重后的每一项的个数~
1)首先先挑出想要的数据
grep "uAddress" data.txt | tr "\t" " "|cut -d " " -f 2
对data.txt 进行抓取uAddress关键字,然后使用cut指令找出需要的那一列:
- -d:后面接分隔符
- -f:后面接第几列(和awk的一些用法其实很相似)
需要注意的是,我担心其中的分隔符有一些空行是空格,有一些却是tab制表符,所以这两个指令之间,我使用了tr指令,去把\t全部转化为空格,接着使用cut指令的时候,则可以放心的使用空格作为分隔符了。
看来其中是有挺多的人不太喜欢填写地域~
2)使用sort进行排序,使用uniq进行去重复统计。
完整的指令是:
grep "uAddress" data.txt | tr "\t" " "|cut -d " " -f 2 | sort | uniq -c | sort -r
我们进行了两次sort,第一sort是把地域进行一个排列,方便uniq的去重,第二个sort就是按照逆序从大到小排列出人数,方便我们观看。
可以看到北上广确实是主力,应该也是人多的关系,也有5925人没有填写,看到最后上图找亮点~
三、总结
其他的单行数据筛选,方法上就大同小异了,基本上用上面的指令都能凭凑出想要的结果~关于多行匹配和筛选,有机会我会写一篇文章出来单独玩一玩。
这个专题有兴趣的时候我就会更新,东西也不会写很难,就是有点意思就研究研究,也欢迎大家给出宝贵意见~
附上数据下载地址:
data.txt
http://download.csdn.net/detail/yang8456211/9531336
杨光(atany)原创,转载请注明博主与博文链接,未经博主允许,禁止任何商业用途。
博文地址:http://blog.csdn.net/yang8456211/article/details/51485723
博客地址:http://blog.csdn.net/yang8456211
本文遵循“署名-非商业用途-保持一致”创作公用协议