iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 25
0
AI & Data

看對話學 Python 資料分析,用情境故事帶你入門系列 第 25

Day-25 學會進階資料處理(下),使用 Matplotlib 進行資料觀察

  • 分享至 

  • twitterImage
  •  


學習使用 Matplotlib 來把資料視覺化吧! Licensed by Adobe Stock

Meiko:「Hey,Jason 你說你要跟我講用 Python 畫圖觀察資料的方式,你打算教我什麼啊?」

Jason:「先想一下,平常在公司老闆請做銷售報表的時候,他們都會想看到什麼?」

Meiko:「歐,一般會想要看每天銷售量的變化吧?然後可能會想知道主力產品銷售的數目,然後因為銷售跟時間有很大的關聯性,通常都是週末銷售的數字會比較漂亮!歐,我想起來,這樣跟你前兩天跟我講的人力成本會有關係,訂單少的那幾天,也許就不用那麼多服務生了!」

Jason:「Okay,那我整理一下,我們可能會從幾個方向來看資料,比如說,可以用長條圖看每天銷售的狀況,可以用圓餅圖知道主力產品之間銷售的比例關係,可以用折線圖看看週間和週末的趨勢。」

Meiko:「哇,那我們趕快開始吧!」

Jason:「別急,拿到資料我們一樣先用.head()的方式,了解一下資料有哪些欄位。再用.describe()了解一下數值裡面的最大、最小和平均值。」

我大寶寶拉請到這個連結下載檔案後,再解壓縮,並且上傳到自己的 Colab 檔案上傳區,跟Day-20上傳 json 檔案是一樣的做法。

import pandas as pd
pdCurryInfo=pd.read_excel("currySalesAndServiceInfo_Total.xlsx",sheet_name="Sheet1")
pdCurryInfo.head()

Meiko:「看起來這份資料比前兩天的資料再多了 dayTime 這個欄位,MON 是什麼意思?」

Jaosn:「這是餐廳老闆報表,是星期一到星期日的代稱,會用三個字的簡寫代表英文星期幾的意思?MON 是星期一、TUE 是星期二 依此類推...SUN 就是星期天囉!」

Meiko:「好唷,那我們再來看.describe()有什麼有用的資訊?」

pdCurryInfo.describe()

Jason:「你看平均消費大約是 182元左右,然後顧客對於服務的品質評價還不錯,平均是 4 顆星...」

Meiko:「但好像就沒辦法直接看到銷售的資訊?」

Jason:「哈,因為這就是你需要做的工作拉!那我們就從代表銷售量的長條圖開始吧!在 Python 裡面有一個套件叫做 matplotlib,我們可以先引入 matplotlib 並且使用.pyplot來畫圖!」

import matplotlib.pyplot as plt
x_labels = ['A','B','C']
sales_num = [120,90,60]
plt.bar(x_labels,sales_num)
plt.show()

Meiko:「原來這樣就能畫出一張長條圖了呀!不過我看不太懂!」

Jason:「它其實有跡可循的拉,比如說我們先把 x 軸,和 y 軸想要表達的資料準備好,x_labels表示有三種品項 A、B、C,然後針對這 3 種品項,我們有他們對應的銷售資料sales_num,接下來就是用到plt.bar(x,y)這個方法,把前述x_labels放到 x 的位置,把sales_num放到 y 的位置,最後再用plt.show()的方式,就能畫出圖來囉!」

Meiko:「真的耶,一點都不難!」

Jason:「那接下來就換你拉,請你把日式餐廳一週裡每天的訂單數,用長條圖畫出來!」

Meiko:「一週裡每天的訂單數,那我要先去把這個資料找到才行,不過 x 軸的資訊好像比較簡單,我先做這個好了!先把星期一到星期天的英文名列出來。」

weekNameList=['MON','TUE','WED','THU','FRI','SAT','SUN' ]

Jason:「接下來就是 y 軸的資料囉,你還記得可以用什麼嗎?」

Meiko:「應該可以用.group_by吧!剛好已經有每天的資料,我可以先用這個欄位來分開。」

eachDay=pdCurryInfo.groupby('dayTime')
eachDay.size()

Meiko:「我要怎麼印出特定某一天有多少訂單啊?」

Jason:「你記得.get_group嗎?你可以把剛剛分好的 eachDay 接著用.get_group(某一天)的方式,去把那天的訂單數印出來!」

len(eachDay.get_group("MON"))

Meiko:「歐,所以我們有星期一的資料,那代表如果我把 weekNameList 裡面每一天都跑過,就可以得到一週的資料了!」

Jason:「所以,應該會長這個樣子!我先幫你把整理資料的部份做完了,接下來圖表的部分就交給你了!」

weekNameList=['MON','TUE','WED','THU','FRI','SAT','SUN' ]
order_num_list=list()
for i in range(len(weekNameList)):
  weekName=weekNameList[i]
  order_num=len(eachDay.get_group(weekName))
  order_num_list.append(order_num)
  print (weekName,order_num)

Meiko:「等一下,你多寫了一個order_num_list是做什麼用的?」

Jason:「那是為了存你前一個步驟,把特定日期的order_num裡面的值,因為它是每天的訂單數量這樣我們接下來就可以把這個值當作是 y 軸的內容!」

Meiko:「Okay,那我知道了,x 軸是weekNameList,那麼 y 軸就是order_num_list囉,那我照你上面的例子把plt.bar()的內容寫出來,再用plt.show()印出來!」

import matplotlib.pyplot as plt
weekNameList=['MON','TUE','WED','THU','FRI','SAT','SUN' ]
plt.bar(weekNameList,order_num_list)
plt.show()

Jason:「不錯唷,馬上就印出來了!」

Meiko:「不過,Jason,一般圖表不都是有橫坐標、縱座標的名稱嗎?這張圖好像少了耶什麼?」

Jason:「沒錯,差了一點資訊,在 matplotlib 裡面,會有title代表標題,xlabelylabel就分別是 x 軸和 y 軸的名稱。我們再補充一下資訊。」

import matplotlib.pyplot as plt
weekNameList=['MON','TUE','WED','THU','FRI','SAT','SUN' ]
plt.bar(weekNameList,order_num_list)
plt.title("Week Sales")
plt.xlabel('Week Day')
plt.ylabel('Order Count')
plt.show()

Meiko:「這樣就清楚多囉!」

Jason:「那我們繼續囉,現在有一整週的訂單資料,接下來我們就要來看,日式餐廳裡面每個主餐的銷售量囉!」

Meiko:「這樣老闆就有辦法知道哪個主餐賣得比較好,看是否要調整菜單?」

Jason:「這是一個不錯的方向唷!」

Meiko:「那我一樣用group_bycontent整理一下,」

maindish=pdCurryInfo.groupby('content')
maindish.size()

Meiko:「恩,我可能還要知道一下日式餐廳的主餐有哪些?目前看來每個餐點都有『甘口』、『辛口』的差別。」

Jason:「主要有 4 種主餐『牛肉咖喱』、『豬排咖哩』、『雞肉咖哩』、『可樂餅咖哩』!」

content_type=['牛肉咖喱','豬排咖哩','雞肉咖哩','可樂餅咖哩']

Meiko:「可是因為我們'content'這個欄位裡面是把口味直接寫在一起,要想一下怎麼知道特定主菜如何計算?」

Jason:「我幫你整理一下,在這一週裡面 4 種主菜,分別賣出的份數如下...」

content_total=['甘口牛肉咖喱','辛口牛肉咖喱','甘口豬排咖哩','辛口豬排咖哩','甘口雞肉咖哩','辛口雞肉咖哩','甘口可樂餅咖哩','辛口可樂餅咖哩']
maindish_count_list=list()
beef=0
pork=0
chicken=0
croquette=0
for i in range(len(content_total)):
  content=content_total[i]
  maindish_count=len(maindish.get_group(content))
  maindish_count_list.append(maindish_count)
  print (content,maindish_count)

order_sales=[187,158,176,147]

Meiko:「所以我們接下來就可以來畫圓餅圖囉!」

Jason:「哈哈,對啊,我把剛幫你整理出來 4 種主菜的銷售狀況,搭配標籤labels就可以用plt.pie去畫出來一個完整的圓餅圖囉!」

labels = ['beef','pork','chicken','croquette']      # 製作圓餅圖的類別標籤
order_sales=[187,158,176,147]
maindish_dist = order_sales                         # 製作圓餅圖的數值

plt.pie(maindish_dist,                  # 數值
        labels = labels,                # 標籤
        autopct = "%1.1f%%",            # 將數值百分比並留到小數點一位
        pctdistance = 0.5,              # 數字距圓心的距離
        textprops = {"fontsize" : 16},  # 文字大小
        shadow=True)                    # 設定陰影

 
plt.axis('equal')     # 使圓餅圖比例相等
plt.title("Pie chart of curry sales", {"fontsize" : 18})  # 設定標題及其文字大小
plt.show()

Meiko:「哇,看起來也蠻專業的耶!」

Jaosn:「當然囉,matplotlib 相當完整,所以想要表達的內容,應跟都可以在 plt.pie()參數裡面寫出來,該怎麼設定你就照著裡面的做法就可以囉!」

Meiko:「看來一點也不難麻,我想餐廳老闆最重視的應該是業績吧,要怎麼樣從資料裡面把業績整理起來給老闆看?」

Jason:「沒錯,你可以用每天來區分,我教你用一招很快的方式找到星期一的銷售量!」

pdCurryInfo[pdCurryInfo['dayTime']=='MON'].price.sum()

Meiko:「歐,Jason 只要一行程式碼就搞定了呀!」

Jason:「對啊,我先用判斷是,先去 pdCurryInfo裡面當欄位dayTime=='MON代表我要看星期一的時間,接著外層有一個pdCurryInfo[內層判斷].price.sum()就是去找到'price'欄位,再用.sum()累加起來,一行就搞定了啊!」

Meiko:「那我就要接著用for-loop把每一天的銷售量寫出來囉!」

weekSales=list()
for i in range(len(weekNameList)):
  weekName=weekNameList[i]
  weekSale=pdCurryInfo[pdCurryInfo['dayTime']==weekName].price.sum()
  weekSales.append(weekSale)
print (weekSales)

Jason:「最後,很快地,我們也可以用plt.plot(x,y)把一週的銷售量找出來!x 軸就可以帶入weekNameList,然後 y 軸就可以帶入weekSales!」

plt.plot(weekNameList,weekSales)
plt.title('Week Sales')
plt.xlabel('Week Day')
plt.ylabel('Sale')
plt.show()

Meiko:「那如果我想合併訂單和銷售量的資訊,要怎麼辦?說不定可以看出來什麼趨勢?」

Jason:「可以呀,不過要多做一點事就是...像下面這樣,我們要用到.sublplots()的方式,設定fig還有兩個 axis,分別是 ax1 和 ax2 這樣我們才能畫出 2 個不同的 Y 座標軸。當然囉,因為 X 座標軸都是同樣的資訊,我們就不用重新設定!」

#設定資料
data1 = order_num_list
data2 = weekSales
t = weekNameList

#Plot graph with 2 y axes
fig, ax1 = plt.subplots()

#畫出訂單數長方圖
ax1.bar(t, data1)
ax1.set_xlabel('Week Day')

# 將資料 1 設定成藍色
ax1.set_ylabel('Order Count', color='b')
[tl.set_color('b') for tl in ax1.get_yticklabels()]

#利用.twinx()在右方畫出 sales  的 y 軸,並劃出銷售額折線圖
ax2 = ax1.twinx()
#Plot a line
ax2.plot(t, data2, 'r-')

# 將資料 2 設定成紅色
ax2.set_ylabel('Sales', color='r')
[tl.set_color('r') for tl in ax2.get_yticklabels()]
plt.title('Sales and Orders')
plt.show()

Meiko:「哇,這張圖蠻厲害的,同時有訂單數還有銷售額!我看到有.twinx()這是什麼?」

Jason:「它就是告訴程式說我要在同一張圖有 2 個不同的 y 軸座標!」

Meiko:「那[tl.set_color('r') for tl in ax2.get_yticklabels()]這個好像自兩段程式碼都有出現?」

Jason:「這個只是要讓左邊的 y 軸座標顏色和長方圖一樣,右邊的 y 軸座標顏色和折線圖一樣囉!」

Meiko:「這樣我就完全懂了,那這張圖綁在一起看,能夠看出什麼額外的資訊嗎?」

Jason:「明顯看到訂單數量是和銷售額可能有正相關,如果想知道更細部的資訊,可能要有多幾個星期的資料!但是通常老闆看到這樣的現象,就知道應該要想辦法多贈加訂單,就可以帶更多生意了!」

Meiko:「說不定老闆已經開始思考跟外送平台合作,多做一些外送的生意,就可以增加訂單了!」

Jason:「不錯唷!這樣不需要增加餐廳內的空間,還可以增加訂單數量!真是一個好方法,」

牛刀小試

我大寶寶~拉,今天我們談了用 Matplotlib ,將資料用圖檔的方式呈現出來,透過長方圖、圓餅圖及曲線圖,把餐廳的銷售資料做一番整理,除了學會如何撰寫程式畫出圖檔之外,過程中我們也做了一些資料處理的工作,這些必要的先期準備工作做完,才做得到資料視覺化。此外,重點還是觀察這些資料後,能夠做出什麼商業決策,這才是最有價值的一部分唷!

給大寶寶留言、分享、鼓勵

歡迎登入留言跟我分享你的想法唷!(登入不麻煩,點一下 FB 登入就可以留言了!)

1.喜歡這樣方式學 Python 的朋友請留言『+1』
2.如果前面的內容忘記了,趕快看一下大寶寶這一系列的看對話學 Python 資料分析,用情境故事帶你入門的列表!就能夠繼續 Happy Coding 囉!


上一篇
Day-24 學會進階資料處理(中),處理數據背後的商業邏輯
下一篇
Day-26 在本機端安裝 Anaconda,不用連網也能寫 Python
系列文
看對話學 Python 資料分析,用情境故事帶你入門30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言