C13-2 通過文件操作對GAFATA股票可視化的經(jīng)歷

看到學習群中有戰(zhàn)友自行開始研究pandas等相關庫的數(shù)據(jù)分析應用,自愧不如,得抓緊腳步,只能在其基礎上自己試試文件操作該如何實現(xiàn)。
1、實現(xiàn)環(huán)境python3;需要的包:os,pandas_datareader中的data,matplotlib,pandas;
2、pandas_datareader庫可用于從不同財經(jīng)數(shù)據(jù)平臺讀取需要的數(shù)據(jù),數(shù)據(jù)全面,包含全球主要股市。我們選擇雅虎財經(jīng)來獲取數(shù)據(jù)。將其讀取的數(shù)據(jù)存儲在本地,因為需要翻墻所以存儲于本地方便代碼調(diào)試,防止網(wǎng)絡不穩(wěn)定重復鏈接增加鏈接中斷的風險。先看看其中的屬性和方法都有哪些:


dir()獲取屬性.png

表示看不懂,具體參數(shù)使用見鏈接

  http://www.itdecent.cn/p/ed947ada9331?utm_campaign=haruki&utm_content=note&utm_medium=reader_share&utm_source=weixin

3、將其可按照json格式存儲為csv文件,但是默認會將日期列剔除,(補充:看了官方文檔才知道,并不是把日期剔除人是默認按照列的名字為第一關鍵字columns,索引——日期為第二關鍵字進行的數(shù)據(jù)存儲,如果要把每一天的數(shù)據(jù)一一對應,需要orient關鍵字指定為index,并且默認存儲日期為時間戳的格式),不利于可視化;


json格式的csv文件.png
  pd.read_json()      

讀取文件默認是按照日期索引讀取,但讀取出的文件并不包括日期;文件的每一列相當于一個帶關鍵字的列表;可通過.key或['key']方式直接調(diào)用;具體操作可見C12-3。在這里不建議用json格式讀取和存儲。
4、將其按照csv格式存儲;


csv格式存為真正的csv文件.png
  pd.read_csv()      

讀取出的是標準csv格式文件,但需要對日期做額外的處理;

  dateparse1 = lambda dates: pd.datetime.strptime(dates, '%Y-%m-%d')      

需要注意的是python3默認就是用utf-8方式編碼,讀取時對日期這樣的字節(jié)格式并不需要再去定義編碼方式,也就是說直接去掉python2中要用到的encoding='utf-8'就好;否則會引發(fā)“UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte”,這樣的錯誤。

將日期作為索引去讀取文件時,讀取的數(shù)據(jù)會自動忽略日期這一關鍵字,相當于被覆蓋;并且讀取為日期格式時,以ns(納秒)為默認轉(zhuǎn)換方式。


日期為索引讀取文件.png

因為我們需要得出每只股票的年增長率,所以需要很方便的得到第一個日期的收盤價和最后一個日期的收盤價,然后算出年增長率。

  def c_ratio(d_close):
"""
analyse the incresing ratio of a stock
:param d_close:
:return: a num
"""
o_price = d_close.Close[0]
c_price = d_close.Close[-1]
# 跟上述方式效果相同
# o_price = d_close['Close'][0]
# c_price = d_close['Close'][-1]
# 計算數(shù)據(jù),通過round方法四舍五入,取小數(shù)點后四位數(shù),在換算為百分比
ratio = '%.2f%%' % (round(((c_price - o_price) / o_price), ndigits=4) * 100)

return ratio       

需要注意的是,按照指定索引去讀取的數(shù)據(jù)結構,每一列相當于列表,可通過[-1]的方式輕松找到最后一個數(shù);如果不指定日期為索引,pandas默認會為數(shù)據(jù)建立相應的索引,值得注意的是并不會對每列數(shù)據(jù)按照索引進行深加工將其轉(zhuǎn)變?yōu)镾eries,而是ndarray。如此將不能很方便的找到最后一個數(shù)據(jù)用于計算(如果用的話);因為按csv格式讀取是按行讀取,如果不事先看數(shù)據(jù),不知道最后一行到底是多少。


不指定索引的數(shù)據(jù).png

但通過指定索引,如果用plt.plot(data)的方式將不能自動按照日期來成圖,而是按照默認索引;如果要用上述方式成圖需指定日期列,會發(fā)現(xiàn)日期列被覆蓋,將索引重新賦給日期字典,還需要對每一行都用apply方法建立關聯(lián)。所以二者是一對矛盾,還未研究透。如果用別的列來建立索引,仍然不能當做Series來看待,求增長率時將不能用[0]、[-1]的方式輕松找到最后一個數(shù)。


Volume為索引的Close數(shù)據(jù).png

所以最簡便的辦法就是指定日期為索引,直接使用指定數(shù)據(jù)列去繪圖的方式來可視化,也就是df['key].plot(自定義設置)(補充:看文檔之后,原來這種成圖方式是pandas自帶的成圖模式,可直接用索引成圖,并非pyplot中的方式),不再需要指定橫坐標——日期;

  d_g['Close'].plot(label="Google" + '^' + str(c_ratio(d_g)))     
最終結果.png

pandas不能直接用文件格式不匹配的方式讀取相應文件,會出錯,但csv和json可以通過運算方式轉(zhuǎn)換;

最終結果是這樣:


可視化結果.png

代碼如下:

  # !/usr/bin/env python
  # -*- encoding: utf-8 -*-

  """
  Attempt to make a graph compare with some stocks
  """

  import os
  import pandas as pd
  from pandas_datareader import data
  import matplotlib.pyplot as plt

  # 對應股票名稱和對應代碼
  dic = {'谷歌': 'GOOG', '亞馬遜': 'AMZN', '臉書': 'FB',
          '阿里巴巴': 'BABA', '騰訊': '0700.hk', '蘋果': 'AAPL', }

  # Set the date
  start_date = '2017-1-1'
  end_date = '2018-1-1'

  # Attempt to check the files, if it does'n exit,try to get it.
  if (os.path.exists('./google_to.csv') and os.path.exists('./Amazon_to.csv') and      
      os.path.exists('./FB_to.csv') and os.path.exists('./ali_to.csv') and
      os.path.exists('./apple_to.csv') and os.path.exists('./tencent_to.csv')
      ):
      dateparse1 = lambda dates: pd.datetime.strptime(dates, '%Y-%m-%d')      

      d_g = pd.read_csv('./google_to.csv',skiprows=0, index_col='Date',      
                        date_parser=dateparse1, parse_dates=True,
                        )
      d_am = pd.read_csv('./Amazon_to.csv', skiprows=0, index_col='Date',      
                         date_parser=dateparse1, parse_dates=True,
                         )
      d_f = pd.read_csv('./FB_to.csv', skiprows=0, index_col='Date',      
                         date_parser=dateparse1, parse_dates=True,
                        )
      d_a = pd.read_csv('./apple_to.csv', skiprows=0, index_col='Date',      
                        date_parser=dateparse1, parse_dates=True,
                        )
      d_ten = pd.read_csv('./tencent_to.csv', skiprows=0, index_col='Date',      
                          date_parser=dateparse1, parse_dates=True,
                          )
      d_baba = pd.read_csv('./ali_to.csv', skiprows=0, index_col='Date',
                           date_parser=dateparse1, parse_dates=True,
                          )
  else:
      d_g = data.get_data_yahoo(dic['谷歌'], start_date, end_date)
      try:
          with open('./google_to.csv', 'w') as f:
              f.write(d_g.to_csv())
      except IOError:
          print ("Please check your code,dedicate space.")
      else:
          d_g.head()      #文件操作后會釋放變量,這一行在執(zhí)行時并不顯示

      d_am = data.get_data_yahoo(dic['亞馬遜'], start_date, end_date)
      try:
          with open('./Amazon_to.csv', 'w') as f:
              f.write(d_am.to_csv())
      except IOError:
          print ("Please check your code,dedicate space.")
      else:
          pass

      d_f = data.get_data_yahoo(dic['臉書'], start_date, end_date)
      try:
          with open('./FB_to.csv', 'w') as f:
              f.write(d_f.to_csv())
      except IOError:
          print ("Please check your code,dedicate space.")
      else:
          pass

      d_a = data.get_data_yahoo(dic['蘋果'], start_date, end_date)
      try:
          with open('./apple_to.csv', 'w') as f:
              f.write(d_a.to_csv())
      except IOError:
          print ("Please check your code,dedicate space.")
      else:
          pass

      d_ten = data.get_data_yahoo(dic['騰訊'], start_date, end_date)
      try:
          with open('./tencent_to.csv', 'w') as f:
              f.write(d_ten.to_csv())
      except IOError:
          print ("Please check your code,dedicate space.")
      else:
          pass

      d_baba = data.get_data_yahoo(dic['阿里巴巴'], start_date, end_date)
      try:
          with open('./ali_to.csv', 'w') as f:
              f.write(d_baba.to_csv())
      except IOError:
          print ("Please check your code,dedicate space.")
      else:
          pass


  def c_ratio(d_close):
      """
      analyse the incresing ratio of a stock
      :param d_close:
      :return: a num
      """
      o_price = d_close.Close[0]      
      c_price = d_close.Close[-1]      

      # o_price = d_close['Close'][0]      
      # c_price = d_close['Close'][-1]      

      ratio = '%.2f%%' % (round(((c_price - o_price) / o_price), ndigits=4) * 100)      

      return ratio

  # print(c_ratio(d_g))      # 測試代碼用
  
 # Set the font to support Chinese
  plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']      
  plt.rcParams['axes.unicode_minus'] = False

  # Let's make grapha
  fig = plt.figure(dpi=128, figsize=(10, 6))
  # d_g['date'] = d_g.index
  # plt.plot(d_g['date'], d_g['Close'], color='r',
  #          label='Google'+ '^' + str(c_ratio(d_g)))
  d_g['Close'].plot(label="Google" + '^' + str(c_ratio(d_g)))
  d_am['Close'].plot(label='Amazon' + '^' + str(c_ratio(d_am)))      
  d_f['Close'].plot(label='Facebook' + '^' + str(c_ratio(d_f)))      
  d_a['Close'].plot(label='Apple' + '^' + str(c_ratio(d_a)))
  d_ten['Close'].plot(label='Tencent' + '^' + str(c_ratio(d_ten)))      
  d_baba['Close'].plot(label='Alibaba' + '^' + str(c_ratio(d_baba)))      

  plt.title('2017GAFATA組合股價年增長趨勢', fontsize=20)
  plt.xlabel('日  期', fontsize=16)
  plt.ylabel('收盤價格', fontsize=16)
  plt.tick_params(axis='both', labelsize=12, which='major')
  plt.grid(True)
  plt.legend(loc=2)

  plt.show()
  # plt.savefig('GAFATA.png', bbox='tight')      

編寫代碼過程中的不足:
1、對pandas還是不熟,需要看文檔系統(tǒng)學習,對不同格式數(shù)據(jù)操作和優(yōu)劣要有系統(tǒng)認知;
2、對matplotlib還是不熟,圖層設置總是想不起該是哪些方法,還需要多練習;
3、文件操作要考慮很多因素,所以需要經(jīng)常鍛煉用try方法來寫代碼;如果有比較有效的內(nèi)建函數(shù)可以判斷,就直接用函數(shù);
4、對python的錯誤類型了解不深入,還需加強;
5、利用單個股票數(shù)據(jù)首先驗證想法,再去實現(xiàn)全部會是個不錯的選擇;
6、為實現(xiàn)某一功能的代碼塊編寫代碼注釋是需要養(yǎng)成的習慣;
7、因為有時候偶要用python2,見C12-5,重寫了一份matplotlibrc文件內(nèi)容是TkAGG模式,python3中不太支持plot,移動圖層會出現(xiàn)編碼錯誤的警告,所以還是需要刪除該文件,使用3默認的API。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容