Bash玩转脚本3之几个指令有趣的筛选京东评价

来源:互联网 发布:linux网卡优先级 编辑:程序博客网 时间:2024/06/07 08:16

Bash玩转脚本3之几个指令有趣的筛选京东评价

今天在工作中遇到了一个筛选和去重问题,饶有兴致祭出Mac(为了跟公司同步,写Android一直用Win~),三两个指令搞定了去重复筛选问题,回到家中意犹未尽,决定总结一下这些年使用bash做数据筛选和去重的经验。

传送门:
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
本文遵循“署名-非商业用途-保持一致”创作公用协议

1 0