Visualizing Health Risk

媒体在处理健康风险数据时很容易出错。数据可视化可以提供帮助。 — 2015 年 11 月,国际癌症研究机构(世界卫生组织的一部分)报告说,食用 50 克加工肉类(例如培根或香肠)与肠癌风险增加 18% 相关[ 1]。媒体报道了这个听起来很吓人的增长……

Visualizing Health Risk

媒体在处理健康风险数据时很容易出错。数据可视化可以提供帮助。

2015 年 11 月,国际癌症研究机构(世界卫生组织的一部分)报告说,食用 50 克加工肉类——例如培根或香肠——与肠癌风险增加 18% 相关[1 ]。[0]

媒体报道了这种听起来吓人的增长,但媒体并未明确表示这是一种相对风险,而不是绝对风险。换句话说,这是风险的增加,而不是实际风险。

可疑的报道可能是因为像“X 让你患上癌症”这样的耸人听闻的标题对于某些报纸来说难以抗拒,但有时媒体会误解,因为数据被不一定了解所呈现内容的记者误解了。

在整个人群中,患肠癌的风险约为 6%。增加 18% 意味着风险上升到 7% 左右。

6 * 1.18 = 7.08

因此,从绝对值来看,风险增加了 1%——这是一个不那么可怕的数字,而且不太可能让人们放弃偶尔吃英式早餐或培根三明治。

展示统计数据真正影响的简单可视化比简单地报告数字更容易理解。例如,条形图可以显示 1% 的增幅有多小。

一项调查人们对重大健康事件(例如中风或死亡)风险的理解的研究[2]发现,简单的条形图确实可以有效地传达风险。尽管在一项类似的研究[3] 中得出的结论是饼图更可取。然而,David Speigelhalter 在其出色的著作《统计的艺术》[4] 中建议图标阵列会更好。

那么该选择哪一个呢?

我将在 Jupyter 笔记本中编写一些 Python 代码,以查看一些用于可视化风险的选项,包括条形图、热图、图标数组和饼图。如果您想继续,请将每个代码块复制到一个新单元格中。您可以在我的 Github 存储库中找到指向整个笔记本的链接。首先导入这些库。[0]

import random
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd

Construct the data

下面的代码构建了一个数据框,该数据框代表 100 人以及将患癌症的人数。 6 人会偶然患上癌症,6 人中有 18% 会因食用加工肉类而得癌症(我在代码中使用培根来表示任何加工肉类)。其余的不会得癌症。

data = pd.DataFrame()
pop = 100 # total population
chance = 6 # number who get cancer by chance
bacon = int(6 * 0.18) # number who get cancer by eating bacon
none = pop - chance - bacon # number who won't get cancer
data['Non-sufferer'] = [none]
data['Sufferer by Chance'] = [chance]
data['Bacon Eater'] = [bacon]

首先,我们将绘制一些条形图,看看它是否更能代表吃培根的风险。我们将使用 Pandas 的绘图功能来做到这一点。

Bar charts

下面的条形图比原始数据更能说明额外的风险。与总人口相比,Bacon Eater 列很小。

data.plot.bar(figsize=(8,5))

这很清楚,但作为堆叠图表会更好吗?

data.plot.bar(stacked=True,figsize=(8,5))

当然,数字是相同的,但条形图的顶层不是很明显,所以可能第一个条形图更可取。

高宽比在很大程度上隐藏了培根食者,那么如果我们将它们转过来变成单杠呢?

data.plot.barh(figsize=(8,5))
data.plot.barh(stacked=True,figsize=(8,5))

在这种情况下,堆积图更清晰,但这主要是由于图的大小和比例。

像这样的图表可能比原始百分比更好,但并不是特别有吸引力。也许我们可以做得更好。

Pie chart

让我们尝试一个饼图。

data.T.plot.pie(subplots=True,figsize=(8,5))

有时饼图根本不清楚,特别是当有多个类别要表示时。然而,这个只有 3 个不同的数据位,所以绘制并在显示相对比例方面做得很好。

我为这些图表中的每一个都使用了默认配色方案——最好更改颜色以突出显示较少数量的培根食者。

但让我们看一些完全不同的东西——热图。

Heat maps

为此,我将使用 Seaborn 数据可视化包。但是,首先,数据需要以不同的方式表示。我将构建一个 10 x 10 的网格,每个单元格代表一个没有癌症的人,谁偶然感染了这种疾病,或者谁屈服于过多的培根。

我首先制作代表 3 个不同类别的 3 个数组,然后将它们拼接成一个单一的一维数组。

# Arrays of the different cases
a1 = [0]*data['Non-sufferer'].values[0]
a2 = [1]*data['Sufferer by Chance'].values[0]
a3 = [2]*data['Bacon Eater'].values[0]
# Stitch them together
a1.extend(a2)
a1.extend(a3)

然后我把它变成一个 10 x 10 的网格。

# Create a grid from the array
b = np.array(a1).reshape((10,10))

Seaborn 热图实际上适用于连续变量,而不是我们这里的离散变量。因此,我将颜色图设置为仅 3 种颜色以映射到 3 个类别,适当地调整了颜色条(图例)并设置了正确的标签。

# Plot the grid as a heat map in Seaborn
fig, ax = plt.subplots(figsize=(8,5))
sns.heatmap(b,
linewidths=0.5,
yticklabels=False,
xticklabels=False,
cmap=['lightblue','royalblue','midnightblue']
)
# Customize legend
colorbar = ax.collections[0].colorbar
colorbar.set_ticks([0.5,1,1.5])
colorbar.set_ticklabels(['Cancer-free','Cancer by chance','Bacon Eater'])

结果是这样的。

这确实很好地显示了这一比例,但 Speigelhalter 认为标记的随机分散可能会给事件的随机性质带来更好的印象。下面的代码与上面的代码几乎相同,只是我在将一维数组转换为网格之前对其进行了洗牌(随机化)。

# Shuffle the data and redrawrandom.shuffle(a1)
b2 = np.array(a1).reshape((10,10))
fig, ax = plt.subplots(figsize=(8,5))
sns.heatmap(b2,
linewidths=0.5,
yticklabels=False,
xticklabels=False,
cmap=['lightblue','royalblue','midnightblue']
)
# Customize legend
colorbar = ax.collections[0].colorbar
colorbar.set_ticks([0.5,1,1.5])
colorbar.set_ticklabels(['Cancer-free','Cancer by chance','Bacon Eater'])

这是不是更好地反映了这种情况?

在我看来,这是一个更好的代表,可能是迄今为止最好的图表。但是让我们看看 Speigelhalter 对图标数组的建议是否更清楚。

Icon array

一个更个性化的图表可能是一个图标数组,它使用我们习惯于看到的东西作为人的代表。这是来自开源 Bootstrap 图标集合的图标:[0]

我不知道有任何简单的方法可以使用我迄今为止使用的任何技术创建图标数组,因此我在下面编写了一个解决方案,使用 Python 创建一个 HTML 表,类似于上一个热图,但是用图标而不是瓷砖。 HTML 然后用 IPython 函数显示来显示。这里有相当多的代码,但它非常简单。

# Use icons to represent people and draw them in an HTML table

from IPython import display

# Create three icons of different colours
personOrange = """<i class="bi-person-fill"
style="font-size: 1rem;
color: orange;"></i>"""
personRed = """<i class="bi-person-fill"
style="font-size: 1rem;
color: red;"></i>"""
personGrey = """<i class="bi-person-fill"
style="font-size: 1rem;
color: grey;"></i>"""

# The first part of the HTML

head = """
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.3.0/font/bootstrap-icons.css">

<div">
"""

# The last part of the HTML
tail = "</div>"

# The middle
rows=""
for r in range(0,b2.shape[1]):
rows = rows + "<tr style='background-color:#f0f0f0'>"
td = ""
for c in range(0,b2.shape[0]):
icon = personGrey
if b2[c][r] == 1:
icon = personOrange
elif b2[c][r] == 2:
icon = personRed
td = td + f"<td>{icon}</td>"
rows = rows + td + "</tr>"

legend = f"""
<div style="display:inline-block;padding:10px">
{personRed} Bacon Eater with cancer<br/>
{personOrange} Cancer by chance <br/>
{personGrey} Cancer free
</div>
"""

table = "<table style='display:inline-block'>"+rows+"</table>"

table = head + table + legend + tail

display.HTML(table)

这为我们提供了 Speigelhalter 青睐的图标阵列,虽然我倾向于同意他的判断,但只有进行适当的调查才能证明他是正确的。

我认为这行得通。图标的随机分布给出了感染疾病的随机性的正确印象,并且图标的使用使其感觉更加个人化 – 就好像其中一个图标实际上代表了我一样。我改变了颜色,因为较小的标记需要更亮一点,我想。

总的来说,我觉得这是最有效的图表。

因此,快速浏览一些可以帮助您更清楚地传达健康(或任何其他类型)风险的选项。我会对你的想法很感兴趣,所以如果你有意见、批评或其他想法,请在下面发表评论。

一如既往,感谢您的阅读。我希望你觉得它很有趣,并会看看我的 Github 存储库中的代码。[0]

如果您对我的其他文章感兴趣,可以在 Medium 上浏览我的个人资料或在我的网站上查看。您还可以订阅我的时事通讯 Technofile,以便收到新文章的通知。[0]

Notes

[1]IARC 专着评估红肉和加工肉类的消费[0]

[2] 比较图标阵列与条形图对风险信息偏好和理解的影响:在线随机研究结果,Peter Scalia ,Danielle C. Schubbe,Emily S. Lu,Marie-Anne Durand,Jorge Frascara,Guillermina Noel,A. James O’Malley,Glyn Elwyn 发布时间:2021 年 7 月 23 日,PLOS One https://doi.org/10.1371/journal.pone.0253644[0]

[3] 为面临颈动脉狭窄治疗选择的患者呈现基于时间的中风和死亡风险:患​​者更喜欢饼图而不是图标阵列 PeterScalia。 A. James.O’Malley、Marie-AnneDurand、Philip P.Goodney、Glyn Elwyn,患者教育和咨询第 102 卷,第 10 期,2019 年 10 月 https://doi.org/10.1016/j.pec.2019.05.004[0]

[4] 这句话出自优秀著作《统计的艺术:如何从数据中学习》,David Spiegelhalter,2021 年(附属链接)[0]

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
心中带点小风骚的头像心中带点小风骚普通用户
上一篇 2022年5月12日
下一篇 2022年5月12日