視覺化數據-平行座標圖

Raven
隨筆趣事
Published in
11 min readJul 1, 2023
Photo by Maksym Tymchyk 🇺🇦 on Unsplash

我們經常遇到排名,還有比較數據不同變量之間關係等場景。

同一項排名或許可以用柱狀圖,但是如何體現排名的波動呢?除了折線圖之外,還有沒有別的選擇?

一組數據的分佈可以用直方圖,兩組數據之間的關係可以用散點圖,三組數據可以用氣泡圖,那四組、五組數據該怎麼辦?今天,我們介紹的平行座標線圖,就是要幫你解決這些問題!

用途

當擁有多個維度與多分組時,可使用平行座標圖,觀看不同指標在不同群體的表現(數值型),如下圖:

實驗室測量了各種水果和蔬菜中含有的各種碳水化合物的量

種類

平行線圖的缺點是,當數據密集時,圖表容易變得混亂,線條難以辨認。解決這個問題的最好辦法是通過一種名為Brushing的技術。

用顏色強化,同時淡化所有其他線條,讓我們能更集中研究感興趣的部分,並濾除干擾數據。

使用Python實作

本文章使用 Olympics 2021來時座。 該數據集包含:

  • 參加過的團隊: country, disciplines
  • 參加過的運動員: country, athletes
  • 最終獎牌統計: country, rank, total medals, and the split across gold, silver, bronze medals

接著我們總結一下國家、運動員人數、參加的項目、排名和獎牌數,並嘗試找到一些問題的答案:

  • 通常一個國家派出多少名運動員? 分布在哪些科系? 一個國家獲得多少枚獎牌?
  • 運動員越多的國家贏得的獎牌就越多嗎?
  • 參加更多科系的國家是否贏得更多獎牌?

讓我們看以下的分析:

df_teams = pd.read_excel("dataset/Teams.xlsx")
df_atheletes = pd.read_excel("dataset/Athletes.xlsx")
df_medals = pd.read_excel("dataset/Medals.xlsx")
df_entries = pd.read_excel("dataset/EntriesGender.xlsx")
print(df_teams.info())
print(df_atheletes.info())
print(df_medals.info())
print(df_entries.info())

沒有數據缺失,因此不需要特定的缺失數據處理:

讓我們找到每個國家參加的科系數量以及每個國家參加的運動員人數,並將這些數據合併到一個dataframe:

df.sort_values(by='Rank', inplace=True)
df.reset_index(inplace=True)
df.drop(columns=['index'], inplace=True)
df.head(10)

Plot using Bar Charts

首先,我們使用條形圖繪製每個國家的運動員、科系、排名和獎牌數據。 為了更好的可讀性,僅使用前 20 個:

查看這 4 個單獨的圖表後,我們可以得出一些見解:

  • 排名前五的國家有300+名運動員參加10+個項項目,獲得50+枚獎牌,其中金牌有20+枚
  • 日本雖然派出了 570 多名運動員參加 20 項比賽(比所有國家都多),但只以 60 枚獎牌和 27 枚金牌位居第三
  • 反之,中國派出了 400 名運動員參加15項目,以 88 塊獎牌和 37 塊金牌位居第二

這很好。 但是,如果我們可以使用單一且更直覺的可視化來得出類似的見解呢?

Plot Parallel Coordinates using pandas

讓我們使用 pandas 套件繪製 20 個國家/地區的圖:

df_20 = df.head(20).copy()
df_20 = df_20[['Country', 'Athletes', 'Discipline', 'Rank', 'Total Medals', 'Gold Medals', 'Silver Medals', 'Bronze Medals']]
plt.figure(figsize=(16,8))
pd.plotting.parallel_coordinates(df_20, 'Country', color=('#556270', '#4ECDC4', '#C7F464'))

對於 pandas 套件,它有兩個缺點:

  1. 我們無法控制各個軸的比例
  2. 我們不能單點或多點某個指標(國家)

這邊筆者介紹使用ploty來更好地控制各種參數。

Parallel Coordinates plot using plotly

在我們深入探討之前,我們先來了解一下情節。 Plotly 是一個 Python 圖形庫,可在線製作交互式、高質量的圖形。 提供2個interface:

  1. Plotly Express,一個易於使用的高級interface,可生成易於設計的圖形。 它在內部使用圖形對象。
  2. Plotly Graph Objects,一個更詳細的interface,可用於更好的控制。

一般情況下,平行坐標圖應該具有豐富的交互性。 沿軸拖動線條以過濾區域,並在繪圖上拖動軸名稱以重新排列變量。

NOTE:

  • pip install plotly
  • fig.show() 不會渲染圖片在 github

Use plotly express interface

在帶有 px.parallel_coordinates 的平行坐標圖中,DataFrame 的每一行(或樣本)都由穿過一組平行軸的折線標記表示,每個平行軸對應一個維度。

import plotly.express as px
df_ = df.copy()

# color : Values from this column are used to assign color to the poly lines.
# dimensions: Values from these columns form the axes in the plot.
fig = px.parallel_coordinates(df_, color="Rank", dimensions=['Rank', 'Athletes', 'Discipline','Total Medals'],
color_continuous_scale=px.colors.diverging.Tealrose,
color_continuous_midpoint=2)
fig.show()

看起來有改進的,但可以更好!

Use Plotly’s graph_objects interface

plotly.graph_objects.Parcoords 允許對粒度級別進行控制 — 每個軸的範圍、刻度值、軸的標籤等。

Parallel Coordinates Plot using plotly graph objects

還有一個問題。 美國獲得的獎牌最多,但顯示在底部。 因此,存在不必要的縱橫交錯的線。 這不是很直觀。 我們希望看到按降序排列的國家/地區:

# Let's reverse the min and max values for the Rank, so that the country with top rank comes on the top. 
dimensions = list([ dict(range=(df_['Rank'].max(), df_['Rank'].min()), tickvals = df_['Rank'], ticktext = df_['Country'],label='Country', values=df_['Rank']),
dict(range=(df_['Athletes'].min(),df_['Athletes'].max()),label='Athletes', values=df_['Athletes']),
dict(range=(df_['Discipline'].min(),df_['Discipline'].max()),label='Discipline', values=df_['Discipline']),
dict(range=(df_['Total Medals'].min(), df_['Total Medals'].max()),label='Total Medals', values=df_['Total Medals']),
dict(range=(df_['Gold Medals'].min(), df_['Gold Medals'].max()), label='Gold Medals', values=df_['Gold Medals']),
dict(range=(df_['Silver Medals'].min(), df_['Silver Medals'].max()),label='Silver Medals', values=df_['Silver Medals']),
dict(range=(df_['Bronze Medals'].min(), df_['Bronze Medals'].max()),label='Bronze Medals', values=df_['Bronze Medals']),
])
fig = go.Figure(data= go.Parcoords(line = dict(color = df_['Rank'], colorscale = 'agsunset'), dimensions = dimensions))
fig.update_layout(width=1200, height=800,margin=dict(l=150, r=60, t=60, b=40))
fig.show()

現在看起來好多了。 如果順著排名第一的美國隊看,可以看到共有614名運動員參加了18個分項的比賽,總共獲得了113枚獎牌,其中39枚是金牌。

而中國隊則派出了400名運動員參加15個項目,以88枚獎牌和37枚金牌位居第二。

從這張圖表中我們可以得出以下與之前基本相同的見解。 透過一張平行座標圖!

可互動性

對於龐大的數據集,平行坐標圖往往會變得混亂。 在這種情況下,我們就需要互動性。 使用互動性,可以過濾或突出顯示數據的某些部分。 軸的順序也可以以最佳方式調整,以便出現變量之間的模式或相關性。

Ploty平行坐標圖支援可互動性,例如:

  • 沿軸拖動線條以過濾區域
  • 在繪圖上拖動軸名稱以重新排列變量
看左上,強化視覺

結論

我們實作了平行坐標圖(可視化)如何用於高維多元數值數據,以得出有意義的見解。 為了生成平行坐標圖,我們使用了 Plotly套件,它提供了許多方便的函數。

優點:

  • 平行座標圖將高維度數據表示為二維可視化

缺點:

  • 當數據密集時,圖表容易變得混亂,線條難以辨認
  • 同上,若維度太大,使用到sider,使用者體驗不佳。
  • 只適用於數值型資料,若有其他型資料(類別、日期等),需自行轉換成數值型資料

下一篇,筆者將介紹桑基(Sankey)圖,以及其應用。

--

--

Raven
隨筆趣事

熱愛寫code,平時遇到有趣的事情,也會上來寫寫,抒發自己的心情。