2018年6月18日 星期一

文字雲 word cloud in python

這篇也是因為工作上需要,所以用Python進行文字雲的分析,想要從常用字詞,進行資料的分類,預期的結果除了統計常用字詞的次數以外,還有好像很炫但要細心看的文字雲圖式,這次做的是【以五月天30首熱門歌曲文字分析,統計出常用字詞,並以五月天 Mayday 的logo視覺化】 (如有侵權請告知,我很怕被吉...)


插個題外話,寫著寫這(其實是貼著貼著),覺得應該寫一系列叫做【輕輕鬆鬆複製貼上 寫Python】,Keep Calm and Copy Paste Series#2 (Keep calm 系列的典故請看這,看個blog順便學學歷史,做個好深宅)

圖片來源: The Keep Calm-o-matic

回到主題,如果要文字分析產生文字雲,有很多工具或網站可以直接使用,但如果想要用自己的字典跟特殊的停用字句,還是需要自己動手做。既然Python也不難寫,就來動手做一下,以後也好累積自己的字典跟停用詞句,以後也方便自己做分析分類。
這次是用五月天 在KKBOX 2018/6 最流行的30首歌詞分析,目的是知道哪些字詞是常用的語句,在應用上滿多種的,如果是分析PTT,那就等於是特定主題的輿情分析,其他領域可以是文章分類等非結構化的文章判斷,那就來看一看程式跟結果吧:

    • Step 1 Import 與定義變數


  1. # coding: utf-8
  2. # 部分參考: https://ithelp.ithome.com.tw/articles/10192043
  3. # 非常感謝王選仲大大
  4. # 部分參考 http://blog.fukuball.com/ru-he-shi-yong-jieba-jie-ba-zhong-wen-fen-ci-cheng-shi/
  5. # 非禪感謝林志傑 Fukuball大大
  6. # 字典來自 https://git.oschina.net/fxsjy/jieba
  7. # 真的是做最好的中文分词组件
  8. #
  9.  
  10. from PIL import Image
  11. import matplotlib.pyplot as plt
  12. from wordcloud import WordCloud, ImageColorGenerator
  13. import jieba
  14. import numpy as np
  15. from collections import Counter
  16.  
    • Step 2 利用Jieba切字
  1. #要分析的來源,這個範例是五月天30首歌
  2. text_from_file_with_apath = open(r'lyrics.txt', "r",encoding="utf-8").read()
  3.  
  4. #設定字典
  5. jieba.set_dictionary('dict.txt.big')
  6. #設定自訂的字典,譬如五月天的 "動次"
  7. jieba.load_userdict(r'userdict_mayday.txt')
  8.  
  9. #設定停用詞,譬如唱歌會用到的oh,喔
  10. with open(r'stopWord_mayday.txt', 'r', encoding='utf8') as f:
  11. stops = f.read().split('\n')
  12.  
  13. #
  14. #開始段詞與排序,沒錯就這麼簡單就做完了
  15. #
  16. terms = [t for t in jieba.cut(text_from_file_with_apath, cut_all=True) if t not in stops]
  17. sorted(Counter(terms).items(), key=lambda x:x[1], reverse=True)
  18.  
    • Step 3 分析完後丟給文字雲繪圖
  1. #中文繪圖需要中文字體,請自己從windows font目錄抓
  2. #微軟正黑體
  3. font = r'msjh.ttc'
  4. #想要文字雲出現的圖示
  5. mask = np.array(Image.open(r"mayday_mask.png"))
  6.  
  7. #背景顏色預設黑色,改為白色
  8. #mark改用五月天的皇冠
  9. #其他參數請自行參考wordcloud
  10. my_wordcloud = WordCloud(background_color="white",mask=mask,font_path=font,collocations=False, width=2400, height=2400, margin=2)
  11. my_wordcloud.generate_from_frequencies(frequencies=Counter(terms))
  12.  
  13. #產生圖片
  14. plt.figure( figsize=(20,10), facecolor='k')
  15. plt.imshow(my_wordcloud,interpolation='bilinear')
  16. plt.axis("off")
  17. plt.tight_layout(pad=0)
  18. #顯示用
  19. plt.show()
  20.  
  21. #存檔用
  22. #plt.savefig("Mayday_Wordcloud.png")



mayday_mask是五月天的皇冠logo,當作遮罩,套上文字雲後,最後的結果就類似這樣,

看來 "一天"、"快樂"、"相信"、"人生"、"回憶"、"愛"是五月天常用的文字。

如果朋友們有更簡單的方式也歡迎跟小弟交流教學相長~~
如果文字內容或圖片有侵權也請告知

#Python
#資料分析
#Word cloud
#文字雲
#Sky is limit

2018年5月26日 星期六

網路爬蟲開發 - 氣象局自動雨量站-雨量觀測 in Python



  • 前言

近期因為工作上需要氣象局的雨量資料,所以開始找相關的介接程式,從政府資料開放平台 (https://data.gov.tw/) 上面共有2個可以介接的資料來源

  1. 氣象局API: https://data.gov.tw/dataset/9177 
  2. 環保署Opendata: https://data.gov.tw/dataset/7879 

實際上來源都是氣象局,但環保署Opendata的資料集已經整理過是平面的資料表,直接用python pandas 可以直接 read_csv or read_json方式直接讀取,但也許是介接的人太多,效能很差,常常要等很久且抓不到資料,如果要作認真的應用(真的要拿來每小時分析或計算)會很困難,因此這一篇是以氣象局的API方式介接並寫入資料庫。


  • 介接方式
透過氣象局Open Data API取得資料,資料經過整理後,再寫入MS SQL Server

  • 前提
必須在氣象局 Open Data 網站 (http://opendata.cwb.gov.tw) 註冊帳號並取得授權碼,如果有很多資料集的應用,需要詳細研讀解氣象局呼叫方式。

    • Step 1 Import 與定義變數
  1. # coding: utf-8
  2.  
  3. #
  4. # Purpose: 自中華民國氣象局 Open Data 取得自動雨量站 每10分鐘雨量資料
  5. # Remark: 解析json資料有參考 https://github.com/leafwind/cwb-cache 非常感謝
  6. #
  7. import logging
  8. import pandas as pd
  9. import requests
  10. from datetime import datetime
  11. import sqlalchemy
  12.  
  13. #氣象局API網址
  14. CWB_URL = 'http://opendata.cwb.gov.tw/api/v1/rest/datastore/'
  15. #自動雨量站 資料集代號
  16. DATA_ID = 'O-A0002-001'
  17. #氣象局 OPEN DATA 授權碼,需要自行修改
  18. AUTH_KEY = 'CWB-OOOOOOOO-OOOO-OOOO-OOOO-OOOOOOOOOOOO'
  19. #目的地 SQL Server 的連結字串,需要自行修改
  20. SQL_CONNECTION_STRING = "mssql+pyodbc://[account]:[password]@[SqlServer]:1433/[Database]?driver=SQL+Server+Native+Client+11.0"
  21. #目的地 SQL Server Table名稱,需要自行修改
  22. DEST_TABLE = 'tb_Rainfall_API'
    • Step 2 取得API的資料集
這段用function方式模組化程式,感謝 leafwind的大作 https://github.com/leafwind/cwb-cache

  1. def get_data_from_cwb(data_id, auth_key, params={}):
  2. '''limit, offset, format, locationName, elementName, sort'''
  3. logging.info('getting data from CWB...')
  4.  
  5. dest_url = CWB_URL + '{}'.format(data_id)
  6. r = requests.get(dest_url, headers={'Authorization': auth_key})
  7. params_list = ['{}={}'.format(key, params[key]) for key in params]
  8. params_str = '?' + '&'.join(params_list)
  9. dest_url += params_str
  10. logging.debug('dest_url: {}'.format(dest_url))
  11. if r.status_code != 200:
  12. logging.error('r.status_code: {}'.format(r.status_code))
  13. return None
  14.  
  15. data = r.json()
  16. if data.get('success') != 'true':
  17. return None
  18. return data
    • Step 3 解析API資料成為Dataframe
雖然概念上很簡單,但是因為解析那段有點麻煩,所以沒辦法很直覺的爬回來就準備寫入資料庫,所以需要轉換,可以直接呼叫這個網址當範例 (只查兩站,速度比較快),我們需要的資料是藍色框框,records\location 向下的資料,其中 weatherElement 是雨量的值。呼叫的function 如下。


  1. def parse_json_to_dataframe(data):
  2. columns = ['stationId','locationName','lat','lon', 'obstime','ELEV','RAIN','MIN_10','HOUR_3','HOUR_6','HOUR_12','HOUR_24','NOW']
  3. df = pd.DataFrame(columns=columns)
  4. dataDic = {}
  5. locations = data['records']['location']
  6. row = -1
  7. for l in locations:
  8. row = row + 1
  9. dataDic['stationId'] = l['stationId']
  10. dataDic['locationName'] = l['locationName']
  11. dataDic['obstime'] = l['time']['obsTime']
  12. dataDic['lat'] = l['lat']
  13. dataDic['lon'] = l['lon']
  14. factors = l['weatherElement']
  15. for f in factors:
  16. factor_name = f['elementName']
  17. dataDic[factor_name] = f['elementValue']
  18. for key in dataDic.keys():
  19. df.loc[row,key] = dataDic[key]
  20.  
  21. return df


    • Step4 主程式:取得資料、解析成為資料表的格式、寫入資料庫
  1. if __name__ == '__main__':
  2. json_data = get_data_from_cwb(DATA_ID, AUTH_KEY, {})
  3. df = parse_json_to_dataframe(json_data)
  4. df['InsertDatetime']=datetime.now()
  5.  
  6. # In[9]:
  7.  
  8. #寫入資料庫
  9.  
  10. engine = sqlalchemy.create_engine(SQL_CONNECTION_STRING)
  11. conn = engine.connect()
  12.  
  13. df.to_sql(DEST_TABLE,engine,if_exists='append')
  14.  
  15. #確認資料庫結果
  16. rs = conn.execute('SELECT TOP 10 * FROM ' + DEST_TABLE +' with (nolock) ORDER BY InsertDatetime desc ')
  17. _result = pd.DataFrame(rs.fetchall())
  18. _result.columns = rs.keys()
  19. conn.close()
  20.  
  21. _result
  22.  

  • Step5 進入資料庫的資料處理
對於這個資料集,會有一些額外的資料面要處理,如雨量的監測值-998轉成0等等,小弟認為這些是資料庫端處理會比較方便,譬如寫一個 stored procedure 或 trigger處理資料,這些就給各位依照自己的需求再調整了。



進入資料庫後,就容易進行後續的應用、計算與分析了!
如果朋友們有更簡單的方式也歡迎跟小弟交流切磋~~

#Python
#Crawler
#氣象局
#環保署
#雨量
#Sky is limit