這裏利用Jake Vanderplas所著的《Python數據科學手冊》一書中的數據,學習畫圖。html
數據地址:https://raw.githubusercontent.com/jakevdp/data-CDCbirths/master/births.csvgit
準備工做:先導入matplotlib和pandas,用pandas讀取csv文件,而後建立一個圖像和一個座標軸github
import pandas as pd from matplotlib import pyplot as plt birth=pd.read_csv(r"https://raw.githubusercontent.com/jakevdp/data-CDCbirths/master/births.csv") fig,ax=plt.subplots()
咱們想要畫一個反映天天平均出生人數的折線圖,看看節假日是否對出生人數有影響。學習
折線圖: ax.plot(x,y,marker="-",color="black")spa
這個數據文件比較大,在用print(birth.head())和print(birth.tail())分別查看先後5行數據後,發現day這一列的數據中有null字樣。code
用print(birth[birth["day"]!="null"])命令查看沒有null字樣的數據(此處只截取部分):orm
year month day gender births
0 1969 1 1 F 4046
1 1969 1 1 M 4440
2 1969 1 2 F 4454
3 1969 1 2 M 4548
4 1969 1 3 F 4548
5 1969 1 3 M 4994
6 1969 1 4 F 4440
7 1969 1 4 M 4520
8 1969 1 5 F 4192
9 1969 1 5 M 4198
10 1969 1 6 F 4710
11 1969 1 6 M 4850
12 1969 1 7 F 4646
13 1969 1 7 M 5092
14 1969 1 8 F 4800
15 1969 1 8 M 4934
16 1969 1 9 F 4592
17 1969 1 9 M 4842
用print(birth[birth["day"]=="null"])命令查看有null字樣的數據(此處只截取部分):htm
year month day gender births
15067 1989 1 null F 156749
15068 1989 1 null M 164052
15069 1989 2 null F 146710
15070 1989 2 null M 154047
15071 1989 3 null F 165889
15072 1989 3 null M 174433
15073 1989 4 null F 155689
15074 1989 4 null M 163432
15075 1989 5 null F 163800
15076 1989 5 null M 172892
15077 1989 6 null F 165525
15078 1989 6 null M 173823
15079 1989 7 null F 174054
15080 1989 7 null M 183063
15081 1989 8 null F 178986
15082 1989 8 null M 188074
15083 1989 9 null F 174808
15084 1989 9 null M 182962
能夠看出,從1989年開始,數據畫風突變,此前記錄的是天天的數據,後面記錄的是每月的數據。blog
這裏咱們先把1969年-1988年的數據提取出來進行統計:birth=birth.iloc[:15067],而後用birth.info()命令查看各列數據的類型,發現day這一列數據類型是object,所以須要轉換其數據類型:get
birth["day"]=birth["day"].astype(int)
接下來把year,month和day這三列的數據結合起來,用pd.to_datetime()轉化爲時間序列格式。結果發生了錯誤:
ValueError: cannot assemble the datetimes: 'int' object is unsliceable
網上查找緣由,在Stackoverflow上有人解答說是由於日期可能超出了容許的範圍:
The valid day range is between 1 and 31. Check your data again make sure all the columns are within allowable range.
如今須要把超標的地方找出來,看一看到底是什麼錯誤。用print(birth[birth["day"]>31])命令查看day超過31的地方,結果發現有好多(此處只截取部分):
year month day gender births
62 1969 1 99 F 26
63 1969 1 99 M 38
126 1969 2 99 F 42
127 1969 2 99 M 48
190 1969 3 99 F 64
191 1969 3 99 M 50
254 1969 4 99 F 50
255 1969 4 99 M 66
318 1969 5 99 F 54
319 1969 5 99 M 52
382 1969 6 99 F 54
383 1969 6 99 M 48
446 1969 7 99 F 24
447 1969 7 99 M 44
不清楚是什麼狀況,在這裏先把這些超標數據去除:birth=birth[birth["day"]<=31]。結果發現仍是不對,把數據再調出來看了以後,發現還有一些day超標,好比說2月份還有29號和30號。乾脆在pd.to_datetime()命令中加上errors='coerce'參數,這樣在數據超標的地方,時間序列就會變成NaT:
birth["date"]=pd.to_datetime({"year":birth["year"],"month":birth["month"],"day":birth["day"]},errors='coerce')
運行上述命令--->給birth數據文件添加了一列---「date」,記錄時間序列。
再次查看birth數據後,發如今day超標的地方,date一列已經標上了NaT(此處只截取部分):
year month day gender births date 0 1969 1 1 F 4046 1969-01-01 1 1969 1 1 M 4440 1969-01-01 2 1969 1 2 F 4454 1969-01-02 .. ... ... ... ... ... ... 190 1969 3 99 F 64 NaT 191 1969 3 99 M 50 NaT
如今把date一列中不是null的值提取出來:
birth=birth[birth["date"].notnull()]
接下來製做一個透視表,把1969年-1988年之間各天出生人數的平均數計算出來(此處須要導入numpy):
birth_by_date=pd.pivot_table(birth,values="births",index=["month","day"],aggfunc=np.mean)
birth_by_date透視表以下(此處只截取部分):
births month day 1 1 4009.225 2 4247.400 3 4500.900 4 4571.350 5 4603.625 6 4668.150 7 4706.925 8 4629.650 9 4537.775 ... 12 2 4830.300 3 4758.500 4 4718.725 5 4734.675 6 4683.050 7 4704.325 8 4803.800 9 4793.825
接下來把透視表的index改成時間序列格式,因爲只須要month和day這兩項,year先隨便填一個:
birth_by_date.index=pd.DatetimeIndex([pd.datetime(2000,month,day) for (month,day) in birth_by_date.index])
如今透視表以下(此處只截取部分):
births
2000-01-01 4009.225
2000-01-02 4247.400
2000-01-03 4500.900
2000-01-04 4571.350
2000-01-05 4603.625
2000-01-06 4668.150
2000-01-07 4706.925
2000-01-08 4629.650
2000-01-09 4537.775
終於大功告成!真不敢相信,圖還沒畫,處理數據已經花了那麼多功夫。但在實際工做中,這實際上是很常見的,數據的清洗一般須要花費大部分時間。
接下來以透視表的index爲x軸,values爲y軸,畫折線圖:
ax.plot(birth_by_date.index,birth_by_date.values,"-")
圖像以下:
能夠看出有幾處日期,出生人數驟降,所以須要在這幾個地方進行標註。同時,x軸的刻度值要改爲12個月份,y軸要加上標籤,整個圖再拉長一點,再加上標題。這樣,這個折線圖就基本完美了。
完整代碼以下:
import numpy as np import pandas as pd import matplotlib as mpl from matplotlib import pyplot as plt birth=pd.read_csv(r"https://raw.githubusercontent.com/jakevdp/data-CDCbirths/master/births.csv") fig,ax=plt.subplots(figsize=(12,4)) birth=birth.iloc[:15067] birth["day"]=birth["day"].astype(int) birth["date"]=pd.to_datetime({"year":birth["year"],"month":birth["month"],"day":birth["day"]},errors='coerce') birth=birth[birth["date"].notnull()] birth_by_date=pd.pivot_table(birth,values="births",index=["month","day"],aggfunc=np.mean) birth_by_date.index=pd.DatetimeIndex([pd.datetime(2000,month,day) for (month,day) in birth_by_date.index]) ax.plot(birth_by_date.index,birth_by_date.values,"-") ax.set(ylabel="average daily births",title="USA births by day of year (1969-1988)",xlim=("2000-01","2001-01")) ax.grid(True) #顯示網格 t=birth_by_date.stack() #把透視表展開 #在相應的地方標上節日名稱 ax.text("2000-01-01",t["2000-01-01"],"New Year's Day") ax.text("2000-07-04",t["2000-07-04"]-60,"Independence Day",ha="center") ax.text("2000-09-04",t["2000-09-01"]-60,"Labor Day",ha="center") ax.text("2000-10-31",t["2000-10-31"]-60,"Halloween",ha="center") ax.text("2000-11-25",t["2000-11-27"]-60,"Thanksgiving",ha="center") ax.text("2000-12-25",t["2000-12-25"],"Christmas",ha="right") #設置x軸刻度值爲月份,並使其居中 ax.xaxis.set_major_locator(mpl.dates.MonthLocator()) ax.xaxis.set_minor_locator(mpl.dates.MonthLocator(bymonthday=15)) ax.xaxis.set_major_formatter(plt.NullFormatter()) ax.xaxis.set_minor_formatter(mpl.dates.DateFormatter('%h')) plt.show()
最終圖像以下: