“大資料” 分析首批北京積分落戶同學
寫這篇文章主要是為了告訴大家, 此號還活著~:joy: 都9012年了, 大家還不掌握點"大資料"技能? 哈哈, 開玩笑, 本文主要是一些常用 Shell 命令的綜合應用. (啊, 發現微信公號改版後沒發過, 所以把這段引言也放一下)
標題黨一回, 現如今到處都是各種"大資料", 本文分析物件也就是首批積分落戶的6000多條資料而已, 顯然不能算什麼大資料.
概述
本文是 Shell 的一次綜合應用, 充分利用 Shell 中的管道, 結合常用的 Shell 命令, 如
sort, uniq, cut, grep, awk, sed
等等命令對之前官方公佈的首批北京積分落戶同學進行分析.
目前政府官方資料公示期已過, 已經不能從官方網站下載相應的公示資料了, 後文用到的資料來源於某CSDN部落格(原文裡有連結). 印象中, 我記得當初該官網的這6000多條資料也是一次性就能wget下來的(後端估計沒做限制, 可能稍微調整下介面的分頁引數之類不需要嚴格按照各種分頁多次下載).
問題描述
拿到的是json資料, 格式化之後的json資料主題結構如下所示, rows為陣列, 陣列中元素所代表的object即描述了獲得北京戶口的同學的各種屬性, 例如分數, 排名, 身份證號(後四位打碼了), 還有公司等等資訊. 為了方便大家練習對資料進行試驗, 我將資料附在這裡(原文裡有連結), 如果有侵權, 請聯絡我刪除.
"rows": [{ "id": 62981, "idCard": "32092219721222****", "idCardSHA": "9ef70bde894959a4e4a1d1b2b9592b470294f9e4012a8cf480319665d1a7c1c6", "insertTime": 1539518353000, "integralQualified": 1, "internetAnnual": { "annual": 2018, "id": 43, "insertTime": 1539518353000, "publicityEnd": 1540224000000, "publicityStart": 1539591600000, "publishResultEndDate": 1541679300000, "publishResultStartDate": 1539591600000, "publishResultStatus": 1, "score": 90.75, "status": 1 }, "md5Code": "54e9ff7ce0b004f7141b157f8afc66db", "name": "楊效豐", "pxid": 1, "ranking": 1, "s1": 51, "s10": 0, "s2": 12.59, "s3": 15, "s4": 0, "s5": 4, "s6": 0, "s7": 20, "s8": 20, "s9": 0, "score": 122.59, "unit": "北京利德華福電氣技術有限公司" },
拿到這個檔案, 比如希望你用最快的方法獲得以下資訊, 你將會怎麼做?
-
獲取取得戶口名額最多的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 137"北京華為數字技術有限公司" 73"中央電視臺" 57"北京首鋼建設集團有限公司" 55"百度線上網路技術(北京)有限公司" 48"聯想(北京)有限公司" 40"北京外企人力資源服務有限公司" 40"中國民生銀行股份有限公司" 39"國際商業機器(中國)投資有限公司" 29"中國國際技術智力合作有限公司" 27"華為技術有限公司北京研究所"
獲取取得戶口名額的人中姓氏最多的
看看想通過積分落戶, 最好是姓啥, 哈哈.
"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| ||g' | cut -c 1 | sort | uniq -c | sort -nr -k 1 | head -n 10 541 張 531 王 462 李 376 劉 205 陳 193 楊 166 趙 132 孫 95 郭 95 徐
獲取戶口名字中叫啥名最流行
套路差不多, 不做過多解釋了.
➜積分落戶> 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 51 偉", 39 靜", 38 濤", 36 勇", 36 軍", 32 敏", 31 穎", 30 鵬", 28 傑", 28 峰", # 取名字, 必須包含2個字 ➜積分落戶> grep '"name":' jifenluohu.json| sed 's|"name": "||g' | sed 's|[[:space:]]||g' | cut -c 2-3 | sed'/"/d' | sort | uniq -c | sort -nr -k 1 | head -n 10 19 海濤 19 曉東 12 志強 11 海燕 11 永強 11 建華 10 雪梅 9 海龍 9 麗娜 8 洪濤
作為碼農, 必須得養成對自己得到結果進行自測的習慣, 所以如果對自己的結果不夠自信, 可以正向去計算一下最終的結果.
例如可以簡單grep
一下進行驗證, 叫 "海濤" 的是不是19個.
➜積分落戶> grep '海濤' jifenluohu.json | wc -l 19
獲取年齡分佈
思路是擷取身份證中號碼中代表出生年的4位數, 然後拿當前年份2019減出生年得到年齡, 後面的套路又一樣了.
bc
一個簡單的計算器程式, 瞭解下?
➜shell-train> echo "3+2-5/5" | bc 4 ➜shell-train> echo "3.141592*5-4" | bc 11.707960
#思路1: `cut -c 9-12` 獲取出生年, 拼接表示式 `2019-出生年` 得到年齡. ➜積分落戶> grep '"idCard":' jifenluohu.json| cut -f2 -d: | cut -c 9-12 | xargs -n1 echo 2019 -|bc | sort | uniq -c 3 34 13 35 39 36 109 37 162 38 302 39 507 40 773 41 799 42 813 43 757 44 586 45 507 46 378 47 238 48 4 49 9 50 1 51 4 52 3 53 2 54 5 55 1 56 1 58 1 59 1 60 1 61
awk
是個好東西, 多練練.
# 拿到出生年後, 直接通過 awk 計算結果輸出 ➜積分落戶> grep '"idCard":' jifenluohu.json| cut -f2 -d: | cut -c 9-12 |awk '{print 2019-$1}' | sort | uniq -c 3 34 13 35 39 36 109 37 162 38 302 39 507 40 773 41 799 42 813 43 757 44 586 45 507 46 378 47 238 48 4 49 9 50 1 51 4 52 3 53 2 54 5 55 1 56 1 58 1 59 1 60 1 61
獲取取得戶口的同學戶籍地top10
有時候, 我們在寫Shell的時候, 為了debug方便, 可能會將一些中間結果快取到檔案中, 後續以該檔案為基礎進行後續的計算.
比如先拿到top10的身份證中代表的戶籍地的四位編碼, 這裡需要藉助另外的一個表示身份證戶籍地的編碼來進行對應. 藉此機會解釋下
join
這個命令.
# 身份證前4位為例, 拿到戶籍地 grep '"idCard":' jifenluohu.json| cut -f2 -d: | cut -c 3-6 | sort | uniq -c | sort -nr -k 1 >topcity.code # 城市列表 ➜積分落戶> more city.csv 11,北京市 1101,北京市市轄區 110101,北京市東城區 110102,北京市西城區 110103,北京市崇文區 110104,北京市宣武區 110105,北京市朝陽區 # grep -E '^[0-9]{4},' city.csv | sed 's|,| |g' > city.code4 ➜ shell-train> head -n 2 city.code4 1101 北京市市轄區 1102 北京市市轄縣 ➜ shell-train> head -n 2 topcity.code 197 1201 156 1302 ➜ shell-train> join usage: join [-a fileno | -v fileno ] [-e string] [-1 field] [-2 field] [-o list] [-t char] file1 file2
其實,
join
就類似sql
中的
...inner join ...on ...
,
-t
分隔符, 預設為空格或tab
.
# 未排序, 所以沒有將所有的匯出(join需要排序) ➜ shell-train> join -1 1 -2 2 city.code4 topcity.code 1201 天津市市轄區 197 1302 河北省唐山市 156 2301 黑龍江哈爾濱市 123 4201 湖北省武漢市 118 6101 陝西省西安市 100 6201 甘肅省蘭州市 59 6501 新疆烏魯木齊市 29 6523 新疆昌吉回族自治州 11
一定需要將結果輸出到檔案, 然後再進行嗎? 其實也不一定. 管道的方式
|
可以將上一個命令的輸出結果作為下一個命令的輸入, 可以通過
<(command)
的方式, 將command
的輸出作為一個檔案輸入.
# 需要排序 ➜ shell-train> join -1 1 -2 2 city.code4 <(head -n 10 topcity.code | sort -k 2) 1201 天津市市轄區 197 1301 河北省石家莊市 114 1302 河北省唐山市 156 1324 河北省保定地區 103 1501 內蒙古呼和浩特市 88 2101 遼寧省瀋陽市 109 2201 吉林省長春市 113 2301 黑龍江哈爾濱市 123 4201 湖北省武漢市 118 6101 陝西省西安市 100
舉個例子paste
用來將兩個檔案按列合併在一起,
➜shell-train> cat paste.f1 hello, i am world, you are ➜shell-train> cat paste.f2 tanglei, wechat is: tangleithu ?, hahaha ➜shell-train> paste paste.f1 paste.f2 hello, i am tanglei, wechat is: tangleithu world, you are?, hahaha
以上用paste
將兩個檔案合併在一起了, 實際上通過
<(cmd)
的方式, 可以不借助外部檔案也能做到. 方法如下:
➜shell-train> paste <(echo "hello, i am \nworld, you are") <(echo "tanglei, wechat is: tangleithu\n?, hahaha") hello, i amtanglei, wechat is: tangleithu world, you are?, hahaha
其他
這裡就不重複多講了, 剩下的問題, 要不你動手試試? 比如看看生日最多的? 再試試獲取 生肖/星座 最多的top10.
有任何疑問, 歡迎留言交流參與交流討論.