TowardsDataScience-博客中文翻译-2020-三十二-
TowardsDataScience 博客中文翻译 2020(三十二)
比利时的新冠肺炎
应用 R 分析比利时新型新冠肺炎冠状病毒

马库斯·斯皮斯克拍摄的照片
介绍
新型新冠肺炎冠状病毒仍在几个国家快速传播,而且似乎不会很快停止,因为许多国家尚未达到高峰。
自其开始扩张以来,世界各地的大量科学家一直在从不同的角度和使用不同的技术分析这种冠状病毒,希望找到一种治疗方法,以阻止其扩张并限制其对公民的影响。
冠状病毒的顶级资源
与此同时,流行病学家、统计学家和数据科学家正在努力更好地了解病毒的传播,以帮助政府和卫生机构做出最佳决策。这导致了大量关于该病毒的在线资源的发布,我收集并整理了一篇文章,涵盖了关于冠状病毒的顶级资源。本文收集了我有机会发现的最好的资源,并对每个资源进行了简要总结。它包括闪亮的应用程序、仪表盘、R 包、博客帖子和数据集。
发布这个集合导致许多读者提交他们的作品,这使得文章更加完整,对任何有兴趣从定量角度分析病毒的人来说更有见地。感谢每一个贡献和帮助我收集和总结这些关于新冠肺炎的资源的人!
鉴于我的专业领域,我无法从医学角度帮助对抗病毒。然而,我仍然想尽我所能做出贡献。从更好地了解这种疾病到将科学家和医生聚集在一起,建立更大、更有影响力的东西,我真诚地希望这个收藏能在一定程度上帮助抗击疫情。
你自己国家的冠状病毒仪表板
除了收到来自世界各地的分析、博客帖子、R 代码和闪亮的应用程序,我意识到许多人都在试图为自己的国家创建一个跟踪冠状病毒传播的仪表板。因此,除了收集顶级 R 资源之外,我还发表了一篇文章,详细介绍了创建特定于某个国家的仪表板的步骤。在这篇文章和一个关于比利时的示例中,查看如何创建这样的仪表板。
该代码已在 GitHub 上发布,并且是开源的,因此每个人都可以复制它并根据自己的国家进行调整。仪表板有意保持简单,这样任何对 R 有最低限度了解的人都可以很容易地复制它,高级用户可以根据他们的需要增强它。
文章的动机、限制和结构
通过查看和整理许多关于新冠肺炎的 R 资源,我有幸阅读了许多关于疾病爆发、不同卫生措施的影响、病例数量预测、疫情长度预测、医院能力等的精彩分析。
此外,我必须承认,一些国家,如中国、韩国、意大利、西班牙、英国和德国受到了很多关注,正如对这些国家所做的分析数量所示。然而,据我所知,在本文发表之日,我不知道有任何针对比利时冠状病毒传播的分析。本文旨在填补这一空白。
在我的统计学博士论文中,我的主要研究兴趣是应用于癌症患者的生存分析(更多信息在我的个人网站的研究部分)。我不是流行病学家,也不具备通过流行病学模型模拟疾病爆发的广博知识。
我通常只写我认为自己熟悉的东西,主要是统计学及其在 R 的应用。在写这篇文章的时候,我很好奇比利时在这种病毒传播方面的立场,我想在 R(对我来说是新的)中研究这种数据,看看会有什么结果。
为了满足我的好奇心,虽然我不是专家,但在这篇文章中,我将复制更多知识渊博的人所做的分析,并将它们应用于我的国家,即比利时。从我到目前为止读到的所有分析中,我决定重复 Tim Churches 和 Holger K. von Jouanne-Diedrich 教授所做的分析。这篇文章是根据他们的文章组合而成的,在这里可以找到这里和这里。他们都对如何模拟冠状病毒的爆发进行了非常翔实的分析,并显示了它的传染性。他们的文章也让我了解了这个话题,尤其是最常见的流行病学模型。我强烈建议感兴趣的读者也阅读他们的最近的文章,以获得更深入的分析和对新冠肺炎疫情传播的更深入的理解。
其他更复杂的分析也是可能的,甚至是更好的,但是我把这个留给这个领域的专家。还要注意,下面的分析只考虑了截至本文发表之日的数据,因此默认情况下,这些结果不应被视为当前的发现。
在文章的剩余部分,我们首先介绍将用于分析比利时冠状病毒爆发的模型。我们还简要讨论并展示了如何计算一个重要的流行病学措施,繁殖数。然后,我们使用我们的模型来分析在没有公共卫生干预的情况下疾病的爆发。最后,我们总结了更先进的工具和技术,可以用来进一步模拟比利时的新冠肺炎。
比利时冠状病毒分析
经典的流行病学模型:SIR 模型
在深入实际应用之前,我们首先介绍将要使用的模型。
有许多流行病学模型,但我们将使用最常见的一个,即先生模型。先生模型可以被复杂化,以纳入病毒爆发的更多特性,但在本文中,我们保持其最简单的版本。Tim Churches 对这个模型的解释以及如何使用 R 来拟合它是如此的好,我将在这里复制它,并做一些小的修改。
传染病爆发的爵士模型背后的基本思想是,有三组(也称为区间)个体:
- S :健康但易患病者(即有被污染的风险)。在疫情开始的时候, S 是整个种群,因为没有人对病毒免疫。
- **我:有传染性的(因此,被感染的)人
- R :已经康复的个人,即曾经受到污染但已经康复或死亡的人。它们不再具有传染性。
随着病毒在人群中的传播,这些群体会随着时间而演变:
- S 减少当个体被污染并转移到传染组 I
- 随着人们康复或死亡,他们从受感染的群体进入康复的群体
为了对疫情的动态进行建模,我们需要三个微分方程来描述每组的变化率,参数如下:
- β,感染率,它控制着 S 和 I 之间的转换
- γ,去除率或回收率,其控制在 I 和 R 之间的转换
形式上,这给出了:

第一个等式(等式。1)声明易感个体的数量( S )随着新感染个体的数量而减少,其中新感染病例是感染率(β)乘以与感染个体( S )有过接触的易感个体数量( I )的结果。
第二个等式(等式。2)说明感染个体数( I )随着新感染个体数(βIS)的增加而增加,减去之前感染的已痊愈者(即γI,即去除率γ乘以感染个体数 I )。
最后,最后一个等式(Eq。3)说明恢复的组随着具有传染性并且恢复或死亡的个体数量的增加而增加(γI)。
流行病的发展过程如下:
- 在疾病爆发前,S 等于整个人口,因为没有人有抗体。
- 在疫情开始时,一旦第一个人被感染, S 减 1, I 也增加 1。
- 这个第一个被感染的个体会感染(在恢复或死亡之前)其他易感的个体。
- 这种动态还在继续,最近被感染的人在康复之前又会感染其他易感人群。
视觉上,我们有:

SIR 模型。来源:凯佐佐木。
在将 SIR 模型拟合到数据之前,第一步是将这些微分方程表示为相对于时间 t 的 R 函数。
*SIR <- function(time, state, parameters) {
par <- as.list(c(state, parameters))
with(par, {
dS <- -beta * I * S / N
dI <- beta * I * S / N - gamma * I
dR <- gamma * I
list(c(dS, dI, dR))
})
}*
用 SIR 模型拟合比利时数据
为了使模型符合数据,我们需要两样东西:
- 这些微分方程的解算器
- 为我们的两个未知参数β和γ寻找最佳值的优化器
来自{deSolve} R 包的函数ode()(针对常微分方程)使得求解方程组变得容易,并且为了找到我们希望估计的参数的最佳值,我们可以使用 base R 中内置的optim()函数
具体来说,我们需要做的是最小化 I(t) 之间的平方差之和,这是在时间 t 时感染室 I 中的人数,以及我们的模型预测的相应病例数。这个量被称为残差平方和( RSS ):

为了拟合比利时发病率数据的模型,我们需要一个初始未感染人群的数值 N 。据维基百科统计,2019 年 11 月比利时人口为 11515793 人。因此,我们将使用 N = 11515793 作为初始未感染人群。
接下来,我们需要用比利时从 2 月 4 日(我们的每日发病率数据开始时)到 3 月 30 日(本文发布时的最后可用日期)的每日累积发病率创建一个向量。然后,我们将把根据这些数据拟合的 SIR 模型预测的发病率与 2 月 4 日以来的实际发病率进行比较。我们还需要初始化 N 、 S 、 I 和 R 的值。请注意,比利时的每日累积发病率摘自 Rami Krispin 开发的[{coronavirus}](https://www.statsandr.com/blog/top-r-resources-on-covid-19-coronavirus/#coronavirus) R 包。
*# devtools::install_github("RamiKrispin/coronavirus")
library(coronavirus)
data(coronavirus)`%>%` <- magrittr::`%>%`# extract the cumulative incidence
df <- coronavirus %>%
dplyr::filter(country == "Belgium") %>%
dplyr::group_by(date, type) %>%
dplyr::summarise(total = sum(cases, na.rm = TRUE)) %>%
tidyr::pivot_wider(
names_from = type,
values_from = total
) %>%
dplyr::arrange(date) %>%
dplyr::ungroup() %>%
dplyr::mutate(active = confirmed - death - recovered) %>%
dplyr::mutate(
confirmed_cum = cumsum(confirmed),
death_cum = cumsum(death),
recovered_cum = cumsum(recovered),
active_cum = cumsum(active)
)# put the daily cumulative incidence numbers for Belgium from
# Feb 4 to March 30 into a vector called Infected
library(lubridate)
Infected <- subset(df, date >= ymd("2020-02-04") & date <= ymd("2020-03-30"))$active_cum# Create an incrementing Day vector the same length as our
# cases vector
Day <- 1:(length(Infected))# now specify initial values for N, S, I and R
N <- 11515793
init <- c(
S = N - Infected[1],
I = Infected[1],
R = 0
)*
注意,需要的是当前感染人数(累计感染人数减去移除人数,即痊愈或死亡人数)。然而,被找回的人数很难获得,并且可能由于漏报偏差而被低估。我因此考虑了 累计 感染人数,这在这里可能不是一个问题,因为在分析时恢复的病例数可以忽略不计。
然后我们需要定义一个函数来计算 RSS ,给定一组β和γ的值。
*# define a function to calculate the residual sum of squares
# (RSS), passing in parameters beta and gamma that are to be
# optimised for the best fit to the incidence data
RSS <- function(parameters) {
names(parameters) <- c("beta", "gamma")
out <- ode(y = init, times = Day, func = SIR, parms = parameters)
fit <- out[, 3]
sum((Infected - fit)^2)
}*
最后,我们可以找到β和γ的值,使观察到的累积发病率(在比利时观察到的)和预测的累积发病率(通过我们的模型预测的)之间的残差平方和最小,从而使 SIR 模型符合我们的数据。我们还需要检查我们的模型是否已经收敛,如下面显示的消息所示:
*# now find the values of beta and gamma that give the
# smallest RSS, which represents the best fit to the data.
# Start with values of 0.5 for each, and constrain them to
# the interval 0 to 1.0# install.packages("deSolve")
library(deSolve)Opt <- optim(c(0.5, 0.5),
RSS,
method = "L-BFGS-B",
lower = c(0, 0),
upper = c(1, 1)
)# check for convergence
Opt$message## [1] "CONVERGENCE: REL_REDUCTION_OF_F <= FACTR*EPSMCH"*
确认收敛。请注意,对于初始值或约束条件的不同选择,您可能会发现不同的估计值。这证明拟合过程是不稳定的。这里有一个潜在的解决方案用于更好的装配过程。
现在我们可以检查β和γ的拟合值:
*Opt_par <- setNames(Opt$par, c("beta", "gamma"))
Opt_par## beta gamma
## 0.5841185 0.4158816*
记住,β控制着 S 和 I 之间的转换(即易感和传染),γ控制着 I 和 R 之间的转换(即传染和痊愈)。然而,这些值并不意味着很多,但我们使用它们来获得我们的 SIR 模型的每个隔间中截至 3 月 30 日用于拟合模型的拟合人数,并将这些拟合值与观察到的(真实)数据进行比较。
*sir_start_date <- "2020-02-04"# time in days for predictions
t <- 1:as.integer(ymd("2020-03-31") - ymd(sir_start_date))# get the fitted values from our SIR model
fitted_cumulative_incidence <- data.frame(ode(
y = init, times = t,
func = SIR, parms = Opt_par
))# add a Date column and the observed incidence data
library(dplyr)
fitted_cumulative_incidence <- fitted_cumulative_incidence %>%
mutate(
Date = ymd(sir_start_date) + days(t - 1),
Country = "Belgium",
cumulative_incident_cases = Infected
)# plot the data
library(ggplot2)
fitted_cumulative_incidence %>%
ggplot(aes(x = Date)) +
geom_line(aes(y = I), colour = "red") +
geom_point(aes(y = cumulative_incident_cases), colour = "blue") +
labs(
y = "Cumulative incidence",
title = "COVID-19 fitted vs observed cumulative incidence, Belgium",
subtitle = "(Red = fitted incidence from SIR model, blue = observed incidence)"
) +
theme_minimal()*

从上图中我们可以看到,不幸的是,观察到的确诊病例数遵循了我们的模型所预期的确诊病例数。这两种趋势重叠的事实表明,疫情在比利时明显处于指数增长阶段。需要更多的数据来观察这一趋势是否会在长期内得到证实。
下图与上图相似,除了 y 轴是在对数标尺上测量的。这种图被称为半对数图,或者更准确地说是对数线性图,因为只有 y 轴以对数标度进行变换。转换对数标度的优势在于,就观察到的和预期的确诊病例数之间的差异而言,它更容易阅读,并且它还显示了观察到的确诊病例数如何不同于指数趋势。
*fitted_cumulative_incidence %>%
ggplot(aes(x = Date)) +
geom_line(aes(y = I), colour = "red") +
geom_point(aes(y = cumulative_incident_cases), colour = "blue") +
labs(
y = "Cumulative incidence",
title = "COVID-19 fitted vs observed cumulative incidence, Belgium",
subtitle = "(Red = fitted incidence from SIR model, blue = observed incidence)"
) +
theme_minimal() +
scale_y_log10(labels = scales::comma)*

该图表明,在疫情开始时至 3 月 12 日,确诊病例数低于指数阶段的预期值。特别是,从 2 月 4 日至 2 月 29 日,确诊病例数保持不变,为 1 例。从 3 月 13 日到 3 月 30 日,确诊病例数量以接近指数的速度持续增加。
我们还注意到 3 月 12 日和 3 月 13 日之间有一个小的跳跃,这可能表明数据收集中的错误,或者测试/筛选方法的变化。
再现数 R0
我们的 SIR 模型看起来与在比利时观察到的累积发病率数据非常吻合,因此我们现在可以使用我们的拟合模型来计算基本生殖数 R0,也称为基本生殖率,它与β和γ密切相关。 2
繁殖数给出了每个感染者感染的平均易感人数。换句话说,繁殖数指的是每一个患病人数中被感染的健康人数。当 R0 > 1 时,疾病开始在人群中传播,但如果 R0 < 1. Usually, the larger the value of R0, the harder it is to control the epidemic and the higher the probability of a pandemic.
Formally, we have:

We can compute it in R:
*Opt_par## beta gamma
## 0.5841185 0.4158816R0 <- as.numeric(Opt_par[1] / Opt_par[2])
R0## [1] 1.404531*
An R0 of 1.4 is below values found by others for COVID-19 and the R0 for SARS and MERS, which are similar diseases also caused by coronavirus. Furthermore, in the literature, it has been estimated that the reproduction number for COVID-19 is approximately 2.7 (with β close to 0.54 and γ close to 0.2). Our reproduction number being lower is mainly due to the fact that the number of confirmed cases stayed constant and equal to 1 at the beginning of the pandemic.
A R0 of 1.4 means that, on average in Belgium, 1.4 persons are infected for each infected person.
For simple models, the proportion of the population that needs to be effectively immunized to prevent sustained spread of the disease, known as the “herd immunity threshold”, has to be larger than 1−1/R0 (Fine, Eames, and Heymann 2011).
The reproduction number of 1.4 we just calculated suggests that, given the formula 1-(1 / 1.4), 28.8% of the population should be immunized to stop the spread of the infection. With a population in Belgium of approximately 11.5 million, this translates into roughly 3.3 million people.
Using our model to analyze the outbreak if there was no intervention
It is instructive to use our model fitted to the first 56 days of available data on confirmed cases in Belgium, to see what would happen if the outbreak were left to run its course, without public health intervention.
*# time in days for predictions
t <- 1:120# get the fitted values from our SIR model
fitted_cumulative_incidence <- data.frame(ode(
y = init, times = t,
func = SIR, parms = Opt_par
))# add a Date column and join the observed incidence data
fitted_cumulative_incidence <- fitted_cumulative_incidence %>%
mutate(
Date = ymd(sir_start_date) + days(t - 1),
Country = "Belgium",
cumulative_incident_cases = I
)# plot the data
fitted_cumulative_incidence %>%
ggplot(aes(x = Date)) +
geom_line(aes(y = I), colour = "red") +
geom_line(aes(y = S), colour = "black") +
geom_line(aes(y = R), colour = "green") +
geom_point(aes(y = c(Infected, rep(NA, length(t) - length(Infected)))),
colour = "blue"
) +
scale_y_continuous(labels = scales::comma) +
labs(y = "Persons", title = "COVID-19 fitted vs observed cumulative incidence, Belgium") +
scale_colour_manual(name = "", values = c(
red = "red", black = "black",
green = "green", blue = "blue"
), labels = c(
"Susceptible",
"Recovered", "Observed incidence", "Infectious"
)) +
theme_minimal()*

The same graph in log scale for the y 轴没有传播,并带有一个可读性更好的图例:
*# plot the data
fitted_cumulative_incidence %>%
ggplot(aes(x = Date)) +
geom_line(aes(y = I, colour = "red")) +
geom_line(aes(y = S, colour = "black")) +
geom_line(aes(y = R, colour = "green")) +
geom_point(aes(y = c(Infected, rep(NA, length(t) - length(Infected))), colour = "blue")) +
scale_y_log10(labels = scales::comma) +
labs(
y = "Persons",
title = "COVID-19 fitted vs observed cumulative incidence, Belgium"
) +
scale_colour_manual(
name = "",
values = c(red = "red", black = "black", green = "green", blue = "blue"),
labels = c("Susceptible", "Observed incidence", "Recovered", "Infectious")
) +
theme_minimal()*

更多汇总统计数据
其他有趣的统计数据可以从我们模型的拟合中计算出来。例如:
- 疫情顶峰的日期
- 重症病例的数量
- 需要特别护理的人数
- 死亡人数
*fit <- fitted_cumulative_incidence# peak of pandemic
fit[fit$I == max(fit$I), c("Date", "I")]## Date I
## 89 2020-05-02 531000.4# severe cases
max_infected <- max(fit$I)
max_infected / 5## [1] 106200.1# cases with need for intensive care
max_infected * 0.06## [1] 31860.03# deaths with supposed 4.5% fatality rate
max_infected * 0.045## [1] 23895.02*
鉴于这些预测,在完全相同的环境下,如果没有任何干预措施来限制疫情的传播,比利时的峰值预计将在 5 月初达到。届时将有大约 530,000 人受到感染,这意味着大约 106,000 个严重病例,大约 32,000 人需要重症监护(鉴于比利时有大约 2000 个重症监护病房,卫生部门将完全不堪重负),以及多达 24,000 人死亡(假设死亡率为 4.5%,如本来源所述)。
至此,我们明白比利时为什么要采取如此严格的遏制措施和规定了!
请注意,这些预测应该非常谨慎。一方面,如上所述,它们是基于相当不切实际的假设(例如,没有公共卫生干预、固定的再生数 R0 等。).利用{projections}包,更高级的预测是可能的,等等(见部分了解更多关于这个问题的信息)。另一方面,我们仍然必须小心谨慎,严格遵循公共卫生干预措施,因为以前的大流行,如西班牙和猪流感,已经表明,令人难以置信的高数字不是不可能的!
本文的目的是用一个简单的流行病学模型来说明这种分析是如何进行的。这些是我们的简单模型产生的数字,我们希望它们是错误的,因为生命的代价是巨大的。
其他注意事项
如前所述, SIR 模型和上面所做的分析相当简单,可能无法真实反映现实。在接下来的章节中,我们将重点介绍五项改进措施,以加强这些分析,并更好地了解冠状病毒在比利时的传播情况。
查明率
在之前的分析和图表中,假设确诊病例数代表所有具有传染性的病例。这与现实相去甚远,因为在官方数字中,只有一部分病例得到筛查、检测和统计。这一比例被称为查明率。
在疾病爆发过程中,确诊率可能会发生变化,特别是如果检测和筛查工作增加,或者如果检测方法发生变化。这种变化的确定率可以通过对发生情况使用加权函数而容易地结合到模型中。
在他的第一篇文章中,Tim Churches 证明了 20%的固定确诊率对于没有干预的模型化疾病爆发没有什么影响,除了它发生得更快一点。
更复杂的模型
更复杂的模型也可以用来更好地反映现实生活中的传播过程。例如,疾病爆发的另一个经典模型是 SEIR 模型。这种扩展模式类似于 SIR 模式,其中 S 代表Sus 可接受, R 代表 R ecovered,但感染者分为两个车厢:
- E 为 E 暴露/感染但无症状
- I 为 I 感染并出现症状
这些模型属于假设固定转换率的连续时间动态模型。还有其他随机模型,允许根据个人属性、社交网络等改变转换率。
使用对数线性模型模拟流行病轨迹
如上所述,当以对数线性图(对数标度上的 y 轴和没有变换的 x 轴)显示时,爆发的初始指数阶段看起来(有些)是线性的。这表明我们可以使用以下形式的简单对数线性模型来模拟流行病的增长和衰退:
log(y) = rt + b
其中 y 为发病率, r 为增长率, t 为自特定时间点(通常为疫情开始)起的天数, b 为截距。在这种情况下,两个对数线性模型,一个是高峰前的生长期,一个是高峰后的衰退期,被拟合到流行病(发病率)曲线。
您经常在新闻中听到的翻倍和减半时间估计值可以从这些对数线性模型中估计出来。此外,这些对数线性模型还可以用于流行病轨迹,以估计流行病增长和衰退阶段的再生数 R0。
R 中的{incidence}包是 R 流行病联盟(RECON) 流行病建模和控制包套件的一部分,使得这种模型的拟合非常方便。
估计有效再生数 Re 的变化
在我们的模型中,我们设置了一个再生数 R0,并保持不变。然而,逐日估算当前的有效再生数 Re 将是有用的,以便跟踪公共卫生干预的有效性,并可能预测发病率曲线何时开始下降。
R 中的{EpiEstim}包可用于估计 Re,并允许考虑除本地传播外来自其他地理区域的人类传播(柯里等人,2013;汤普森等 2019)。
更复杂的预测
除了基于简单 SIR 模型的天真预测之外,更先进和复杂的预测也是可能的,特别是利用{projections}软件包。该软件包使用关于每日发病率、序列间隔和繁殖数的数据来模拟可能的流行轨迹和预测未来发病率。
结论
本文首先(I)描述了可用作背景材料的关于冠状病毒疫情的几个 R 资源(即集合和仪表板),以及(ii)本文背后的动机。然后,我们详细介绍了最常见的流行病学模型,即 SIR 模型,然后将其实际应用于比利时发病率数据。
这导致了在比利时对拟合的和观察的累积发病率的直观比较。这表明,就确诊病例数量而言,新冠肺炎疫情在比利时明显处于指数增长阶段。
然后,我们解释了什么是繁殖数,以及如何在 r 中计算繁殖数。最后,我们的模型用于分析在完全没有公共卫生干预的情况下冠状病毒的爆发。
在这种(可能过于)简单的情况下,比利时新冠肺炎的峰值预计将在 2020 年 5 月初达到,感染人数约为 530,000 人,死亡人数约为 24,000 人。这些非常危言耸听的天真预测凸显了政府采取限制性公共卫生行动的重要性,以及公民采取这些卫生行动以减缓病毒在比利时的传播(或至少减缓到足以让卫生保健系统应对它)的紧迫性。
在这篇文章的结尾,我们描述了五个可以用来进一步分析疾病爆发的改进。
请注意,这篇文章已经在 UCLouvain 进行了演讲。
感谢阅读。我希望这篇文章让你对新冠肺炎冠状病毒在比利时的传播有了很好的了解。请随意使用这篇文章作为分析这种疾病在你自己国家爆发的起点。
对于感兴趣的读者,另请参阅:
- 比利时住院人数和确诊病例数的变化
- 收集冠状病毒方面的顶级资源以获得更多知识
和往常一样,如果您有与本文主题相关的问题或建议,请将其添加为评论,以便其他读者可以从讨论中受益。
相关文章:
- 关于新型新冠肺炎冠状病毒的前 25 个 R 资源
- 如何创建针对贵国的简单冠状病毒仪表板
- 如何在 R 中一次对多个变量进行 t 检验或方差分析,并以更好的方式传达结果
- 如何手动执行单样本 t 检验,并对一个平均值进行 R:检验
参考
柯里,安妮,尼尔·M·费格森,克利斯朵夫·弗雷泽和西蒙·柯西梅兹。2013."一个新的框架和软件来估计流行病期间随时间变化的繁殖数."美国流行病学杂志* 178 卷 9 期。牛津大学出版社:1505-12。*
好的,保罗,肯·伊姆斯和大卫·海曼。2011.“《群体免疫》:粗略指南。”临床传染病* 52 (7)。牛津大学出版社:911–16。*
Thompson,RN,JE·斯托克温,RD van Gaalen,JA Polonsky,ZN Kamvar,PA Demarsh,E Dahlqwist 等,2019 年。"改进传染病爆发期间随时间变化的繁殖数的推断."流行病 29。爱思唯尔:100356。
- 如果您专门针对比利时进行了一些分析,我可以将这些分析包含在我的文章中,报道关于冠状病毒的顶级 R 资源,请随时在评论中或通过联系我让我知道。 ↩
- 如果你需要更深入的理解,请参见詹姆斯·霍兰德·琼斯关于复制号的更详细的注释。 ↩
原载于 2020 年 3 月 31 日 https://statsandr.com*。***
编者注: 迈向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
新冠肺炎在比利时:结束了吗?
比利时新冠肺炎引起的住院率和新增确诊病例数的变化。
介绍
注 1:本文写于 2020 年 5 月 22 日,不经常更新。因此,比利时新冠肺炎的现状可能与下文所述不同。更多剧情更新请看我的 推特 简介。
注 2:这是与 尼可·斯佩布鲁克 教授 凯瑟琳·里纳德 教授 西蒙·德利库尔 和 天使罗萨斯-阿吉雷 的联合作品。
比利时最近开始解除最初为遏制新冠肺炎病毒蔓延而实施的封锁措施。在比利时当局做出这一决定后,我们分析了迄今为止形势的演变。
与我在之前的一篇文章中使用 SIR 模型分析了比利时冠状病毒的爆发相反,在这篇文章中,我们关注的是:
- 住院人数
- 医院里的病人
- 重症监护中的病人
- 新确诊病例
在省和国家一级。
数据来自科学杂志,所有的图都是用[{ggplot2}](https://www.statsandr.com/blog/graphics-in-r-with-ggplot2/) 软件包创建的。
新入院人数
全部的

新冠肺炎比利时医院
从上图可以看出,住院率在所有省份都呈下降趋势(比利时也是如此)。
2020 年 10 月 27 日更新:

比利时的住院治疗
布拉班特的详细情况:

按周期

2020 年 3 月至 10 月比利时的每日 COVID19 住院情况
2020 年 11 月 16 日更新:

比利时期间每天的 COVID19 住院情况
下载图。
在第一波中,林堡省每百万居民平均住院人数最高。在第二次浪潮中,列日和海瑙特努力争取最高税率。除了两个例外(安特卫普和林堡),上个月的情况比 3-4 月更糟糕。在三个省(海瑙特、那慕尔和列日),这一数字增加了一倍多。
在 2020 年 6 月 14 日至 7 月 15 日期间,比利时的 COVID19 住院人数降至非常低的相对水平,但我们未能保持这一水平。既然住院人数不再增加,我们希望随着年底的临近,颜色会再亮一点。
放大

比利时新冠肺炎医院

2021 年 2 月 26 日更新:
比利时正在讨论是否要放松限制。2021 年 2 月 26 日,比利时当局将开会、讨论、辩论并做出决定。新冠肺炎住院治疗的当前水平和趋势可以为他们提供指导:

仍然没有强有力的证据表明比利时的新冠肺炎住院曲线下降。第一波(灰色-日期和曲线)和第二波(蓝色-日期和曲线)之间的比较需要谨慎,但表明当前的住院水平并不像一些人希望的那样低:

放大显示了第一波和第二波省级新冠肺炎水平的更多信息:

这表明,在比利时大多数省份,第二次浪潮导致的住院人数比第一次更多,尽管第一次致命浪潮发出了警告。这也说明了一个事实,即比利时目前的每日住院率仍然高于第一波结束时的水平。
简而言之,坏消息是接触人数和通过接触传播的风险的组合似乎(目前)还不足以导致住院人数大幅减少。然而(简而言之),今天的好消息是人群中已经有了一些免疫力,疫苗接种可能会大大增加这种免疫力。这有助于向下推动曲线。让我们不要失去希望。
医院里的病人
以下是比利时医院病人数量的变化情况:

比利时医院中的 COVID19 患者
我们看到,截至 2020 年 10 月 28 日,比利时医院的 COVID19 患者数量达到第一波高峰。因此,尽管与第一波相比,第二波患者在医院停留的时间较短,但医院仍然越来越拥挤。
因此,如果未来几周医院中的患者数量遵循同样的路径,医院将很快变得过于拥挤,并且将无法接收新患者,因为其最大容量将很快达到(如果这还不是情况……)。
重症监护中的病人
根据短期预测和 99%的置信区间,比利时重症监护中 COVID19 患者的演变如下:

比利时重症监护病房中 COVID19 患者的演变
下载图。
短期预测表明,如果传播速度没有减慢,可能会发生什么。这种放缓是积极的消息。
这些地图显示了各省重症监护患者的总数(如果有比利时人口的话)。顶部的地图显示 3 月至 4 月的最高水平,底部的地图显示当前水平。该图显示了 COVID19 导致的高重症监护使用率。在比利时大多数省份,今天的数字仍然高于 3 月至 4 月的峰值。
观察结果与其他初步迹象一致,如 COVID19 住院趋势(目前相对不稳定),表明传播正在放缓:

下载图。
确诊病例
请注意,报告的新增确诊病例数可能被低估。这一数字不包括未诊断(无症状或症状很少)或未检测的病例。因此,应极其谨慎地解释带有病例数的数字。
按省份

比利时新增确诊新冠肺炎病例
按年龄组和性别
静态
下面是比利时三个不同时期按年龄组和性别分列的病例数的另一个图表:

比利时按年龄组和性别分列的新冠肺炎病例
这一形象化显示了报告病例年龄而不仅仅是总数的重要性。
此外,我们看到,9 月初按年龄组划分的每周病例分布与暑假期间相似,但每周病例数更高。然而,9 月初按年龄组划分的每周病例分布与“第一波”(2020 年 3 月 1 日至 2020 年 5 月 31 日期间)不同。在第一阶段,大多数病例是老年人,而在 9 月初,大多数病例是年轻人。观察冬季不同年龄组的病例分布如何演变将是很有意思的。
上述数字可能与比利时人口结构有关:

比利时人口结构(2019 年)
动态的
此外,还可以动态查看这些信息:

比利时按年龄组和性别划分的新冠肺炎病例-动态版本
随着第二波的更新:

比利时每 100,00 0 例 COVID19 病例的年龄和性别特异性发病率—动态版本
按年龄组、性别和省份

感谢阅读。我们希望这些数字将朝着正确的方向发展。与此同时,请注意安全!
如果你想进一步了解新冠肺炎疫情的发展,有两个选择:
- 不时访问博客,并且
- 加入 Twitter 并关注我们: statsandr ,NikoSpeybroeck&arosas _ agui rre
和往常一样,如果您有与本文主题相关的问题或建议,请将其添加为评论,以便其他读者可以从讨论中受益。
相关文章
原载于 2020 年 5 月 22 日 https://statsandr.com。
编者注: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家,这篇文章的观点不应被解释为专业建议。
欧洲足球联赛中的新冠肺炎

欧洲五大足球国家的职业足球运动员如何感染新冠肺炎病毒
失望之余,当我最喜欢的球队利物浦输给马德里竞技时,我感到一股愤怒在我的血管中流淌。这意味着利物浦足球俱乐部将不再参加本赛季余下的欧洲冠军联赛。此外,这导致了我们持续三个赛季的不败本垒打的结束。
这也标志着一个重要事件的开始,欧洲足球的暂时终结。随着冠状病毒疫情开始像野火一样在全球蔓延,大多数欧洲足球联赛开始关闭并无限期推迟任何体育赛事。因此,接下来的两到三个月将不会有足球比赛。
对我来说,这是一种可怕的方式,因为那次痛苦的损失。欧洲各地的足球俱乐部开始进行多种测试,以了解他们的球员和工作人员是否感染了新冠肺炎病毒。当他们测试他们的球员和工作人员时,他们在网上报告了测试结果,关于谁得到了它以及下一步是什么。
看到许多足球专业人士(工作人员和球员)感染了新冠肺炎,以及它是如何在欧洲传播的,这促使我进行研究,以找出新冠肺炎如何影响五大足球国家(英、西、意、德、法)的欧洲联赛。我不得不阅读多篇文章来找出谁感染了新冠肺炎。
一篇非常有用的文章可以在这里找到。它提供了大量的信息,包括名字,球队,年龄,联赛,在球队中的角色和状态。我决定将所有这些细节一行一行地插入到谷歌的电子表格中。
在记录了 86 个病例后,我遇到了一个障碍,因为我阅读的所有其他文章都没有提供任何关于感染该病毒的人口统计数据的细节。标题是“经过又一轮检测,X 人的新冠肺炎病毒检测呈阳性”我开始绘制图表,显示新冠肺炎如何影响不同的联赛。我创建的图表可以在下面看到。
感染新冠肺炎的职业足球运动员的平均年龄

欧洲五大足球国家的地图,突出显示了感染新冠肺炎的职业足球运动员的平均年龄
在德国,足球专业人士感染新冠肺炎的平均年龄是 23.5 岁,是最少的。第二少的是法国,25.5 分。意大利居中,得分为 27.5。联合王国的平均年龄为 35.8 岁。最高的是西班牙,为 36.33。
各联盟的案件数量

一个条形图,显示了整个联盟的案件数量
在五个主要足球国家中,西班牙西甲记录的案件数量最高,为 32 起。排在第二位的是意甲联赛,记录了 19 起。英超联赛以 17 枚位列第三。德甲以 7 枚位列第四。前三名是法国排名前两名的联赛,分别是法甲和法乙。两者都记录了一个病例。右上角的图例显示了联盟的位置。
基于新冠肺炎案例的团队排名

根据新冠肺炎案例对团队进行排名的水平条形图
阿拉维斯受到重创,因为其组织的 15 名成员感染了新冠肺炎病毒。同样在西班牙的西班牙人受到重创,有 11 人被诊断患有新冠肺炎。第三是意大利的桑普多利亚,记录了 8 例。巴伦西亚和伯恩茅斯排名第四,共有 5 起案件。
结论
在这个项目中,我利用 Tableau 创建了一个地图,显示了各个国家感染新冠肺炎病毒的足球专业人士的平均年龄。我还构建了一个条形图来显示不同联盟中记录了多少个案例。最后,我使用了一个水平条形图,根据感染冠状病毒的人数对各个团队进行排名。
结合这三个图表,我能够构建一个交互式仪表板,并通过 Tableau Public 部署它。这个交互式仪表盘可以在这里查看。
感谢您的阅读。
您可能还会对以下内容感兴趣:
印度的新冠肺炎
新冠肺炎教对印度影响的详细统计分析。

马库斯·温克勒在 Unsplash 上的照片
新冠肺炎是一种由冠状病毒引起的传染病,生物学上称为严重急性呼吸综合征冠状病毒 2 型(新型冠状病毒)。这种疾病于 2019 年 12 月在中国湖北省省会武汉首次被发现,此后蔓延到世界各地。当我写这篇文章时,IST 时间 2020 年 4 月 28 日 00:55,根据谷歌的数据,全世界有 300 万确诊病例,并导致 208,000 人死亡。
在这篇文章中,我将看看印度的现状。我们将看看受疫情影响最严重的地区,以及该国的人数是如何稳步攀升的
首先,我们将导入我将在分析中使用的必要库。
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns%matplotlib inline
%matplotlib notebook
接下来,我们将从我获取信息的地方导入不同的数据表。
covid19_df = pd.read_csv("./datasets/covid_19_india.csv")
individuals_df = pd.read_csv("./datasets/IndividualDetails.csv")excel_file = pd.ExcelFile("./datasets/Indian States Population and Area.xlsx")
indian_states_df = excel_file.parse('Sheet1')
在这个分析中,我使用了三个不同的数据来源。我要感谢 Sudalai Rajkumar 和他的合作者,我从 Kaggle 下载了前两个文件。最后一个数据集是我从 uidai 网站和维基百科上收集的州级 Aadhaar 饱和度数据。
你可以从我的 GitHub 库下载数据集,我在文章末尾附上了链接,或者你也可以从 Kaggle 下载。如果你在网上使用它们,记得给出到期的学分!
让我们看看来自 Kaggle 的 COVID 19 数据集的前几条记录。

covid19_df.head()

covid19_df.tail()
因此,我们可以看到,该数据集提供了该国特定州每天发现的病例数记录。在进一步的检查中,我们发现这个数据集包含 1350 个条目和 9 个特征。这些数据包含了一些重要的数据,比如某个州某一天的确诊人数、死亡人数和治愈人数。确诊病例进一步细分为印度国民和外国人。这个数据集中的细节层次是我最喜欢的!

covid19_df.shape

covid19_df.isna().sum()
在这里,我们看到这个数据集中没有丢失的值,这使我的工作更容易。现在让我们看一下每个州的最新记录,了解一下我们目前的情况。从最后一组记录中,我们可以看到我们拥有截至 2020 年 4 月 25 日的数据。
covid19_df_latest = covid19_df[covid19_df['Date']=="25/04/20"]
covid19_df_latest.head()

covid19_df_latest['Confirmed'].sum()

因此,现在我们已经根据每个州的最新数据筛选了 1318 条记录的数据集。通过检查这些数据,我们看到截至 2020 年 4 月 25 日,印度共有 24,893 例病例。
治国人物
covid19_df_latest = covid19_df_latest.sort_values(by=['Confirmed'], ascending = False)
plt.figure(figsize=(12,8), dpi=80)
plt.bar(covid19_df_latest['State/UnionTerritory'][:5], covid19_df_latest['Confirmed'][:5],
align='center',color='lightgrey')
plt.ylabel('Number of Confirmed Cases', size = 12)
plt.title('States with maximum confirmed cases', size = 16)
plt.show()

显示确诊新冠肺炎阳性病例最多的州的条形图。
在检查上面的可视化,我们看到,马哈拉施特拉邦有最多的案件检查到目前为止。马哈拉施特拉邦接近 7000 例,在我上传这个笔记本的时候可能已经超过了这个数字。根据我们掌握的数据,马哈拉施特拉邦的情况如此严重,以至于印度没有任何其他邦超过这一标准的一半。古吉拉特邦和德里即将达到 3000 例,而拉贾斯坦邦和中央邦只有 2000 多例。
covid19_df_latest['Deaths'].sum()

根据数据集中的数据,印度各邦已有 779 人死亡。我们现在将了解哪些州的死亡人数最多。
covid19_df_latest = covid19_df_latest.sort_values(by=['Deaths'], ascending = False)
plt.figure(figsize=(12,8), dpi=80)
plt.bar(covid19_df_latest['State/UnionTerritory'][:5], covid19_df_latest['Deaths'][:5], align='center',color='lightgrey')
plt.ylabel('Number of Deaths', size = 12)
plt.title('States with maximum deaths', size = 16)
plt.show()

条形图显示了因新冠肺炎死亡人数最多的州。
毫不奇怪,上图中出现的五个状态中的四个也出现在这张图中。马哈拉施特拉邦目前几乎占了印度因新冠肺炎死亡人数的一半。排名第二的古吉拉特邦也没有达到一半。中央邦即将达到三位数,德里和安得拉邦紧随其后。
接下来,我想看看印度各邦每个确诊病例的死亡人数,以便更好地了解可用的医疗设施。
covid19_df_latest['Deaths/Confirmed Cases'] = (covid19_df_latest['Confirmed']/covid19_df_latest['Deaths']).round(2)
covid19_df_latest['Deaths/Confirmed Cases'] = [np.nan if x == float("inf") else x for x in covid19_df_latest['Deaths/Confirmed Cases']]
covid19_df_latest = covid19_df_latest.sort_values(by=['Deaths/Confirmed Cases'], ascending=True, na_position='last')
covid19_df_latest.iloc[:10]

因此,在创建了这个新的衡量标准,并根据这个数字对各州进行排序之后,我来看看这方面最差的十个州。我们看到,在梅加拉亚邦、恰尔肯德邦和阿萨姆邦等一些邦,病例和死亡人数目前都很低,情况似乎得到了控制。但是像旁遮普邦、卡纳塔克邦等其他邦看起来也受到了这种情况的影响。我们将西孟加拉邦排除在整个等式之外,因为该邦已经出现了关于错误发布数字的消息。中央邦、古吉拉特邦和马哈拉施特拉邦也榜上有名。
然而,这些统计数据并不总是提供清晰的画面。印度是一个人口结构多变的国家,没有两个邦是相同的。也许将这些数字等同于一个州的估计人口可能会对整个情况有更好的了解。
每 1000 万例
indian_states_df.head()

现在让我们真正使用你收集的数据集。该数据集提供了截至 2019 年每个州分配的 Aadhaar 卡的数量以及每个州每平方公里的面积等细节。每个州分配的 Aadhaar 卡的数量是一个很好的衡量或估计每个州人口数字的方法。我决定使用这个数字,因为印度政府的官方人口普查是在 2011 年进行的,差距太大,不能使用。我还决定不采用基于以往人口普查预测的各种人口预测数字。
我们现在将从主新冠肺炎数据集中删除一些要素,因为这些细节对我的分析没有太大帮助。我们还会将分配的 Aadhaar 卡的数量列重命名为人口,并放弃面积功能,因为我决定不使用它,因为最近印度各邦和 UTs 进行了更新。
covid19_df_latest = covid19_df_latest.drop(['Sno','Date','Time','ConfirmedIndianNational','ConfirmedForeignNational'], axis = 1)
covid19_df_latest.shape

indian_states_df = indian_states_df[['State', 'Aadhaar assigned as of 2019']]
indian_states_df.columns = ['State/UnionTerritory', 'Population']
indian_states_df.head()

我们现在将人口数据集与主数据集合并,并创建一个名为“每 1000 万病例数”的新要素,以获得更多关于哪些病例受新冠肺炎危机影响更大的信息。我觉得这个新措施现在是一个更加冷静的措施,因为它考虑到了不同州之间存在的人口差异。
covid19_df_latest = pd.merge(covid19_df_latest, indian_states_df, on="State/UnionTerritory")
covid19_df_latest['Cases/10million'] = (covid19_df_latest['Confirmed']/covid19_df_latest['Population'])*10000000
covid19_df_latest.head()

covid19_df_latest.fillna(0, inplace=True)
covid19_df_latest.sort_values(by='Cases/10million', ascending=False)

错过了大约 5 个州,因为我不能把它们放在一张图片里!对不起,读者们!
df = covid19_df_latest[(covid19_df_latest['Confirmed']>=1000) | (covid19_df_latest['Cases/10million']>=200)]
plt.figure(figsize=(12,8), dpi=80)
plt.scatter(covid19_df_latest['Confirmed'], covid19_df_latest['Cases/10million'], alpha=0.5)
plt.xlabel('Number of confirmed Cases', size=12)
plt.ylabel('Number of cases per 10 million people', size=12)
plt.scatter(df['Confirmed'], df['Cases/10million'], color="red")for i in range(df.shape[0]):
plt.annotate(df['State/UnionTerritory'].tolist()[i], xy=(df['Confirmed'].tolist()[i], df['Cases/10million'].tolist()[i]),
xytext = (df['Confirmed'].tolist()[i]+1.0, df['Cases/10million'].tolist()[i]+12.0), size=11)plt.tight_layout()
plt.title('Visualization to display the variation in COVID 19 figures in different Indian states', size=16)
plt.show()

散点图显示了印度不同邦之间新冠肺炎数字的变化。
因此,从图表和视觉效果来看,我们意识到,即使我们把邦人口考虑在内,马哈拉施特拉邦、古吉拉特邦、德里、拉贾斯坦邦和中央邦确实受到了严重影响。除了这些邦,还有其他邦和中央直辖区,如泰米尔纳德邦、北方邦、安得拉邦、泰伦加纳、昌迪加尔和拉达克。然而,拉达克的情况看起来不错,在 20 例确诊病例中,有 14 例已经康复。昌迪加尔也是如此,28 例确诊病例中有 15 例已经康复。
现在我们已经有了每个状态的六个重要特征,我们可以看看这些特征是如何相互关联的,并从中得出一些见解。
plt.figure(figsize = (12,8))
sns.heatmap(covid19_df_latest.corr(), annot=True)

显示不同功能之间相互关系的热图。
我们注意到,一些指标,如确诊、治愈、死亡和每 1000 万人病例数,是非常相关的,我们并不急于去认识其中的原因。
个人数据
接下来,我们来看一下现有的个案数据。在对该数据集进行初步检查时,我们发现该数据集中有大量缺失数据,我们在继续分析时必须考虑这些数据。

individuals_df.isna().sum()individuals_df.iloc[0]

2020 年 1 月 30 日,印度发现首例新冠肺炎病例。这是在喀拉拉邦的特里斯苏尔市发现的。该人有在武汉的旅行史。

individuals_grouped_district = individuals_df.groupby('detected_district')
individuals_grouped_district = individuals_grouped_district['id']
individuals_grouped_district.columns = ['count']
individuals_grouped_district.count().sort_values(ascending=False).head()
接下来,我决定根据发现病例的地区对个人数据进行分组。在做这件事的时候,我必须格外小心,因为这一栏中有一些丢失的数据。从现有数据来看,孟买是全国受灾最严重的地区。它有 2000 多个病例,其次是艾哈迈达巴德。浦那是马哈拉施特拉邦的另一个区,也在这个名单中。所有这些地区都属于我们在前面的图表中看到的州。
individuals_grouped_gender = individuals_df.groupby('gender')
individuals_grouped_gender = pd.DataFrame(individuals_grouped_gender.size().reset_index(name = "count"))
individuals_grouped_gender.head()plt.figure(figsize=(10,6), dpi=80)
barlist = plt.bar(individuals_grouped_gender['gender'], individuals_grouped_gender['count'], align = 'center', color='grey', alpha=0.3)
barlist[1].set_color('r')
plt.ylabel('Count', size=12)
plt.title('Count on the basis of gender', size=16)
plt.show()

基于性别的新冠肺炎案例分布。
继续我们的分析,我想看看病例数是如何根据性别分布的。我们看到在这个分布中没有宇称。从数据来看,在印度,这种病毒对男性的影响似乎大于女性。这也得到不同新闻机构的证实。挖一下谷歌!
印度病例数的进展
在本节中,我们将了解印度的病例数是如何增加的。之后,我们将检查这条曲线,并找出与州级曲线的相似之处。
为了做这个分析,我必须稍微修改一下数据集。我根据诊断数据特征对数据进行了分组,这样我就有了全印度每天检测到的病例数。接下来,我对这个特性进行了累加,并将其添加到一个新的列中。
individuals_grouped_date = individuals_df.groupby('diagnosed_date')
individuals_grouped_date = pd.DataFrame(individuals_grouped_date.size().reset_index(name = "count"))
individuals_grouped_date[['Day','Month','Year']] = individuals_grouped_date.diagnosed_date.apply(
lambda x: pd.Series(str(x).split("/")))
individuals_grouped_date.sort_values(by=['Year','Month','Day'], inplace = True, ascending = True)
individuals_grouped_date.reset_index(inplace = True)
individuals_grouped_date['Cumulative Count'] = individuals_grouped_date['count'].cumsum()
individuals_grouped_date = individuals_grouped_date.drop(['index', 'Day', 'Month', 'Year'], axis = 1)
individuals_grouped_date.head()

individuals_grouped_date.tail()

该数据集包含截至 4 月 20 日的数据。当天,印度共有 18032 例确诊病例。我们注意到数据集包含 1 月 30 日的数据,但不包含中间的数据,因为在此期间没有检测到病例。为了保持连续性,我决定假设 2020 年 3 月 2 日为第一天,因为我们有从那以后每天的数据。
individuals_grouped_date = individuals_grouped_date.iloc[3:]
individuals_grouped_date.reset_index(inplace = True)
individuals_grouped_date.columns = ['Day Number', 'diagnosed_date', 'count', 'Cumulative Count']
individuals_grouped_date['Day Number'] = individuals_grouped_date['Day Number'] - 2
individuals_grouped_dateplt.figure(figsize=(12,8), dpi=80)
plt.plot(individuals_grouped_date['Day Number'], individuals_grouped_date['Cumulative Count'], color="grey", alpha = 0.5)
plt.xlabel('Number of Days', size = 12)
plt.ylabel('Number of Cases', size = 12)
plt.title('How the case count increased in India', size=16)
plt.show()

印度新冠肺炎阳性病例的进展。
在上面的曲线中,我们看到上升或多或少是稳定的,直到第 20 天。在 20-30 之间的区间,曲线稍微倾斜。这种倾斜逐渐增加,在 30 天后,我们看到一个稳定而陡峭的斜坡,没有变平的迹象。这些都是不祥的迹象。
在接下来的几个代码元素中,我准备并处理数据集,根据不同的状态对数据进行分组。在接下来的分析中,我使用了以下五种状态:
- 马哈拉施特拉邦
- 喀拉拉邦
- 德里
- 拉贾斯坦邦
- 古吉拉特邦
covid19_maharashtra = covid19_df[covid19_df['State/UnionTerritory'] == "Maharashtra"]
covid19_maharashtra.head()
covid19_maharashtra.reset_index(inplace = True)
covid19_maharashtra = covid19_maharashtra.drop(['index', 'Sno', 'Time', 'ConfirmedIndianNational', 'ConfirmedForeignNational','Cured'], axis = 1)
covid19_maharashtra.reset_index(inplace = True)
covid19_maharashtra.columns = ['Day Count', 'Date', 'State/UnionTerritory', 'Deaths', 'Confirmed']
covid19_maharashtra['Day Count'] = covid19_maharashtra['Day Count'] + 8
missing_values = pd.DataFrame({"Day Count": [x for x in range(1,8)],
"Date": ["0"+str(x)+"/03/20" for x in range(2,9)],
"State/UnionTerritory": ["Maharashtra"]*7,
"Deaths": [0]*7,
"Confirmed": [0]*7})
covid19_maharashtra = covid19_maharashtra.append(missing_values, ignore_index = True)
covid19_maharashtra = covid19_maharashtra.sort_values(by="Day Count", ascending = True)
covid19_maharashtra.reset_index(drop=True, inplace=True)
print(covid19_maharashtra.shape)
covid19_maharashtra.head()

covid19_kerala = covid19_df[covid19_df['State/UnionTerritory'] == "Kerala"]
covid19_kerala = covid19_kerala.iloc[32:]
covid19_kerala.reset_index(inplace = True)
covid19_kerala = covid19_kerala.drop(['index','Sno', 'Time', 'ConfirmedIndianNational', 'ConfirmedForeignNational','Cured'], axis = 1)
covid19_kerala.reset_index(inplace = True)
covid19_kerala.columns = ['Day Count', 'Date', 'State/UnionTerritory', 'Deaths', 'Confirmed']
covid19_kerala['Day Count'] = covid19_kerala['Day Count'] + 1
print(covid19_kerala.shape)
covid19_kerala.head()

covid19_delhi = covid19_df[covid19_df[‘State/UnionTerritory’] == “Delhi”]
covid19_delhi.reset_index(inplace = True)
covid19_delhi = covid19_delhi.drop([‘index’,’Sno’, ‘Time’, ‘ConfirmedIndianNational’, ‘ConfirmedForeignNational’,’Cured’], axis = 1)
covid19_delhi.reset_index(inplace = True)
covid19_delhi.columns = [‘Day Count’, ‘Date’, ‘State/UnionTerritory’, ‘Deaths’, ‘Confirmed’]
covid19_delhi[‘Day Count’] = covid19_delhi[‘Day Count’] + 1
print(covid19_delhi.shape)
covid19_delhi.head()

covid19_rajasthan = covid19_df[covid19_df['State/UnionTerritory'] == "Rajasthan"]
covid19_rajasthan.reset_index(inplace = True)
covid19_rajasthan = covid19_rajasthan.drop(['index','Sno', 'Time', 'ConfirmedIndianNational', 'ConfirmedForeignNational','Cured'], axis = 1)
covid19_rajasthan.reset_index(inplace = True)
covid19_rajasthan.columns = ['Day Count', 'Date', 'State/UnionTerritory', 'Deaths', 'Confirmed']
covid19_rajasthan['Day Count'] = covid19_rajasthan['Day Count'] + 2
missing_values = pd.DataFrame({"Day Count": [1],
"Date": ["02/03/20"],
"State/UnionTerritory": ["Rajasthan"],
"Deaths": [0],
"Confirmed": [0]})
covid19_rajasthan = covid19_rajasthan.append(missing_values, ignore_index = True)
covid19_rajasthan = covid19_rajasthan.sort_values(by="Day Count", ascending = True)
covid19_rajasthan.reset_index(drop=True, inplace=True)
print(covid19_rajasthan.shape)
covid19_rajasthan.head()

covid19_gujarat = covid19_df[covid19_df['State/UnionTerritory'] == "Gujarat"]
covid19_gujarat.reset_index(inplace = True)
covid19_gujarat = covid19_gujarat.drop(['index','Sno', 'Time', 'ConfirmedIndianNational', 'ConfirmedForeignNational','Cured'], axis = 1)
covid19_gujarat.reset_index(inplace = True)
covid19_gujarat.columns = ['Day Count', 'Date', 'State/UnionTerritory', 'Deaths', 'Confirmed']
covid19_gujarat['Day Count'] = covid19_gujarat['Day Count'] + 19
missing_values = pd.DataFrame({"Day Count": [x for x in range(1,19)],
"Date": [("0" + str(x) if x < 10 else str(x))+"/03/20" for x in range(2,20)],
"State/UnionTerritory": ["Gujarat"]*18,
"Deaths": [0]*18,
"Confirmed": [0]*18})
covid19_gujarat = covid19_gujarat.append(missing_values, ignore_index = True)
covid19_gujarat = covid19_gujarat.sort_values(by="Day Count", ascending = True)
covid19_gujarat.reset_index(drop=True, inplace=True)
print(covid19_gujarat.shape)
covid19_gujarat.head()

所有五个州都有 55 个记录,包含 5 个特征。每个记录代表一天。在这个分析中,为了保持一致,我也决定将 2020 年 3 月 2 日作为第一天。
现在让我们来看看可视化。
plt.figure(figsize=(12,8), dpi=80)
plt.plot(covid19_kerala['Day Count'], covid19_kerala['Confirmed'])
plt.plot(covid19_maharashtra['Day Count'], covid19_maharashtra['Confirmed'])
plt.plot(covid19_delhi['Day Count'], covid19_delhi['Confirmed'])
plt.plot(covid19_rajasthan['Day Count'], covid19_rajasthan['Confirmed'])
plt.plot(covid19_gujarat['Day Count'], covid19_gujarat['Confirmed'])
plt.legend(['Kerala', 'Maharashtra', 'Delhi', 'Rajasthan', 'Gujarat'], loc='upper left')
plt.xlabel('Day Count', size=12)
plt.ylabel('Confirmed Cases Count', size=12)
plt.title('Which states are flattening the curve ?', size = 16)
plt.show()

印度一些邦新冠肺炎病例的进展。
我们看到几乎所有的曲线都遵循着整个国家的曲线。唯一的例外是喀拉拉邦。与其他曲线一样,喀拉拉邦的曲线在 20-30 天内逐渐倾斜。但喀拉拉邦成功做到的是,它没有让曲线进一步倾斜,而是设法让曲线变平。因此,国家已经能够控制局势。
马哈拉施特拉邦的形势看起来确实非常严峻。这条曲线非常陡峭,没有减速的迹象。与其他地区相比,古吉拉特曲线在较晚的时间间隔变陡。它一直保持在控制状态,直到第 30 天,40 天后病情恶化。
作为一个整体,我们防止这场迫在眉睫的危机的唯一方法是拉平曲线。所有邦政府都需要遵循喀拉拉模式。这是唯一一个设法使曲线变平的国家,因此,大多数事情都做对了。是时候我们遵循喀拉拉模式了。
卡格尔邮报:https://www.kaggle.com/pritamguha31/covid-19-in-india
Github 链接:【https://github.com/PritamGuha31/COVID-19-Analysis
意大利的新冠肺炎感染。数学模型和预测
logistic 和指数模型在意大利新冠肺炎病毒感染中的比较。

Viktor Forgacs 在 Unsplash 上拍摄的照片
这些天来,世界正在与一个新的敌人作战,这就是新冠肺炎病毒。
自从在中国首次出现以来,这种病毒在世界上迅速传播。不幸的是,意大利正在记录欧洲新冠肺炎感染人数最高。我们是西方世界面对这个新敌人的第一个国家,我们每天都在与这种病毒的所有经济和社会影响作斗争。
在本文中,我将向您展示 Python 中感染增长的简单数学分析和两个模型,以更好地理解感染的演变。
数据收集
每天,意大利民事保护部门都会刷新累计感染人数数据。此数据在 GitHub 上公开为公开数据:https://raw . githubusercontent . com/PCM-DPC/新冠肺炎/master/dati-andamento-Nazionale/DPC-covid 19-ita-andamento-Nazionale . CSV
我的目标是创建到目前为止的总感染人数的时间序列的模型(即实际感染人数加上已经感染的人数)。这些模型都有参数,将通过曲线拟合来估算。
用 Python 来做吧。
首先,让我们导入一些库。
import pandas as pd
import numpy as np
from datetime import datetime,timedelta
from sklearn.metrics import mean_squared_error
from scipy.optimize import curve_fit
from scipy.optimize import fsolve
import matplotlib.pyplot as plt
%matplotlib inline
现在,我们来看看原始数据。
url = "https://raw.githubusercontent.com/pcm-dpc/COVID-19/master/dati-andamento-nazionale/dpc-covid19-ita-andamento-nazionale.csv"df = pd.read_csv(url)

我们需要的列是“totale_casi ”,它包含迄今为止的累计感染人数。
这是一切开始的原始数据。现在,让我们为我们的分析准备它。
数据准备
首先,我们需要将日期转换成数字。我们将从 1 月 1 日开始休假。
df = df.loc[:,['data','totale_casi']]FMT = '%Y-%m-%d %H:%M:%S'date = df['data']df['data'] = date.map(lambda x : (datetime.strptime(x, FMT) - datetime.strptime("2020-01-01 00:00:00", FMT)).days )

我们现在可以分析我将参加考试的两个模型,它们是逻辑函数和指数函数。
每个模型有三个参数,这些参数将通过对历史数据的曲线拟合计算来估计。
逻辑模型
逻辑斯蒂模型被广泛用于描述人口的增长。感染可以被描述为病原体的增长,因此逻辑模型似乎合理。
这个公式在数据科学家中非常有名,因为它被用在逻辑回归分类器中,并作为神经网络的激活函数。
逻辑函数最通用的表达式是:

在这个公式中,我们有变量 x 即时间和三个参数: a,b,c 。
- a 指感染速度
- b 是发生感染最多的一天
- c 是感染结束时记录的感染者总数
在高时间值时,感染人数越来越接近和 c ,在这一点上我们可以说感染已经结束。该函数在 b 处还有一个拐点,即一阶导数开始降低的点(即感染开始变得不那么具有攻击性并降低的峰值)。
我们用 python 来定义吧。
def logistic_model(x,a,b,c):
return c/(1+np.exp(-(x-b)/a))
我们可以使用 scipy 库的 curve_fit 函数,从原始数据开始估计参数值和误差。
x = list(df.iloc[:,0])
y = list(df.iloc[:,1])fit = curve_fit(logistic_model,x,y,p0=[2,100,20000])
以下是这些值:
- 答 : 3.54
- b : 68.00
- c : 15968.38
该函数也返回协方差矩阵,其对角线值是参数的方差。取它们的平方根,我们可以计算出标准误差。
errors = [np.sqrt(fit[1][i][i]) for i in [0,1,2]]
- a 的标准误差:0.24
- b 的标准误差:1.53
- c 的标准误差:4174.69
这些数字给了我们许多有用的见解。
感染结束时的预期感染人数为 15968+/- 4174。
感染高峰预计在 2020 年 3 月 9 日左右。
预期感染结束时间可以计算为累计感染人数等于到四舍五入到最接近整数的 c 参数的那一天。
我们可以使用 scipy 的 fsolve 函数来数值求解定义感染结束日的方程的根。
sol = int(fsolve(lambda x : logistic_model(x,a,b,c) - int(c),b))
时间是 2020 年 4 月 15 日。
指数模型
逻辑模型描述的是 ain 感染增长将在未来停止,而指数模型描述的是不可阻挡的感染增长。例如,如果一个病人每天感染 2 个病人,1 天后我们会有 2 个感染,2 天后 4 个,3 天后 8 个,依此类推。
最普通的指数函数是:

变量 x 是时间,我们还有参数 a,b,c 。然而,其含义不同于逻辑函数参数。
让我们在 Python 中定义函数,并执行用于逻辑增长的相同曲线拟合过程。
def exponential_model(x,a,b,c):
return a*np.exp(b*(x-c))exp_fit = curve_fit(exponential_model,x,y,p0=[1,1,1])
参数及其标准误差为:
- 一个 : 0.0019 +/- 64.6796
- b : 0.2278 +/- 0.0073
- c : 0.50 +/- 144254.77
情节
我们现在有了可视化结果的所有必要数据。
pred_x = list(range(max(x),sol))
plt.rcParams['figure.figsize'] = [7, 7]plt.rc('font', size=14)# Real data
plt.scatter(x,y,label="Real data",color="red")# Predicted logistic curve
plt.plot(x+pred_x, [logistic_model(i,fit[0][0],fit[0][1],fit[0][2]) for i in x+pred_x], label="Logistic model" )# Predicted exponential curve
plt.plot(x+pred_x, [exponential_model(i,exp_fit[0][0],exp_fit[0][1],exp_fit[0][2]) for i in x+pred_x], label="Exponential model" )plt.legend()
plt.xlabel("Days since 1 January 2020")
plt.ylabel("Total number of infected people")
plt.ylim((min(y)*0.9,c*1.1))plt.show()

两条理论曲线似乎都非常接近实验趋势。哪个做得更好?再来看看残差。
残差分析
残差是每个实验点和相应理论点之间的差。我们可以分析两个模型的残差,以验证最佳拟合曲线。在一级近似中,理论和实验数据之间的均方差越低,越符合。
y_pred_logistic = [logistic_model(i,fit[0][0],fit[0][1],fit[0][2]) for i in x]y_pred_exp = [exponential_model(i,exp_fit[0][0], exp_fit[0][1], exp_fit[0][2]) for i in x]mean_squared_error(y,y_pred_logistic)
mean_squared_error(y,y_pred_exp)
Logistic 模型均方误差:8254.07
指数模型均方误差:16219.82
哪个型号合适?
残差分析似乎指向逻辑模型。很有可能是因为感染应该在未来的某一天结束;即使每个人都会被感染,他们也会发展出适当的免疫防御来避免二次感染。只要病毒不会变异太多(比如流感病毒),就没错。
但是有一点还是让我担心。自从感染开始,我每天都在拟合逻辑曲线,每天我都得到不同的参数值。末感染人数增加,最大感染日往往是当天或次日(这个参数上兼容 1 天的标准误)。这就是为什么我认为,尽管逻辑模型似乎是最合理的一个,但曲线的形状很可能会由于像新感染热点、政府控制感染的行动等外部影响而改变。
这就是为什么我认为这个模型的预测只有在几周内,也就是感染高峰期过后,才会开始变得有用。
编者按:【towardsdatascience.com】是一家以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
新冠肺炎-按美国州和县列出的所有案例的交互式 Power BI 地图
疫情对全国的影响的局部视图


TL;DR 链接到仪表板此处
我和我妻子谈到美国各县是如何在新闻中单独报道新冠肺炎病例的。有很多地图追踪器用于世界和美国的州级报告,但没有多少地图在县一级整理。
她将此视为一项挑战,并在一个晚上就构建了这个惊人的公开可用的 Power BI 交互式仪表盘!
支持仪表板的 API 和数据:
最初,我们将这个令人敬畏的 GitHub API 归功于 GitHub 用户JKSenthil:【https://github.com/JKSenthil/coronavirus-county-api】
,他构建了这个基于 python 的 API,从https://coronavirus.1point3acres.com/en抓取数据
但是,当 1point3acres 更改他们的 html UI 数据格式时,我们遇到了一些问题,这破坏了 API。我最终克隆了 API,并对其进行了编辑,使其起死回生(这占用了我周日的大部分时间)。但是,嘿,一个星期天花在帮助妻子上是值得的。😃
API 分叉和调整:
API 使用 Selenium WebDriver,它运行一个无头 Chrome 来抓取 web URL,并将 API 数据作为 JSON 返回。API 是用 python 编写的,运行在通过 gunicorn 提供服务的 Flask 上,部署并托管在 Heroku 上。我遇到了一些问题:
问题# 1:API 中断是因为 scraper 失败。这源于源 UI 格式的变化。我可以通过调整抓取逻辑来解决这个问题。
问题#2: Heroku 的自由等级意味着我必须限制 gunicorn 的工人数量为 1。这对于应用程序来说不是问题,因为它是唯一请求数据的 API 用户。这些请求每隔几个小时才会刷新一次仪表板。
问题# 3:API 需要一段时间来响应,因为抓取器必须遍历美国所有 3200 多个县来抓取数据。我不得不将 gunicorn 的超时值提高到比默认值更长。
结束语:
总的来说,这是一次很酷的经历,特别是使用 Python 和 Heroku 主机。
我相信这张公共地图也揭示了有趣的县级统计数据和空间分布。随着美国新冠肺炎病例的增加,这一点尤其重要。在#隔离期间,帮助我的妻子做一个数据科学项目也很有趣!
如果您对该主题有任何想法或对仪表盘或所用工具有任何疑问,请通过 LinkedIn 与我联系
这里是交互式仪表盘的链接,它每 24 小时更新一次:新冠肺炎美国仪表盘
新冠肺炎正在改变我们的生活方式,而人工智能正在努力跟上
根据过去行为训练的机器学习模型很难猜测我们的下一步行动

在 Unsplash 上 engin akyurt 拍摄的照片
本周,亚马逊建议我买一加仑的洗手液,谷歌的地理位置记录告诉我总共去过零个地方,YouTube 认为我可能会喜欢看更多的面具制作 DIY 和面包烘焙教程。
显然,自从疫情开始以来,我们的日常生活已经发生了变化。对我们中的许多人来说,我们买什么,去哪里,做什么都和以前有很大的不同。
在国际卫生危机期间,这些变化是意料之中的。然而,对于根据正常人类行为训练的人工智能系统来说,我们的新行动对它们的算法来说是一个相当大的冲击,它们正在努力跟上。
人工智能是一个包含很多东西的宽泛术语,但在这种情况下,我们谈论的是机器学习。这些算法使用大量数据来找到一种模式,并对接下来会发生什么做出有根据的猜测。对于亚马逊来说,这个猜测就是你想买的东西。对于 YouTube 来说,就是你想看的。
无论我们是否意识到这一点,我们的生活已经深深扎根于机器学习模型。除了在线商店和流媒体应用,它们还用于欺诈检测、安全、营销等领域。
但是这些模型只能脱离给它们的数据。当他们遇到一个与他们从中学到的数据相差太大的场景时,他们很难猜到你要做什么。
当新冠肺炎开始影响我们的日常生活时,机器学习算法开始遇到一些问题。
据《麻省理工技术评论》报道,一家公司的预测算法被一次不寻常的批量订单打破。当算法告诉他们重新进货的商品不再与客户购买的商品匹配时,他们注意到了这一点。
类似的用户激增给一家在线流媒体公司使用的推荐算法带来了问题。他们发现用户数据的涌入降低了推荐的准确性。
对于一家信用欺诈检测公司来说,引起警惕的不是如何购买了多少,而是购买了什么。他们发现,人们突然开始购买园艺设备和电动工具,他们的算法通常会将其记录为欺诈性支出。
在这种情况下,公司的工程师们有先见之明,为消费习惯的改变做出了调整。
当发生重大变化时,像这样的修改对于保持机器学习算法的工作是必不可少的。你不能简单地训练自动化系统,然后走开。为了跟上时代,他们需要监督、调整,甚至可能需要一些再培训。
例如,亚马逊调整了他们的算法,以解释他们在购买中看到的变化。
它们通常会为使用其仓库的卖家带来流量,但当疫情开始,人们开始更多地在网上购物时,仓库变得不堪重负。通过调整他们的算法,他们能够让订单更均匀地分配给卖家。
另一家使用机器学习来编写广告电子邮件的公司也对他们的算法进行了一些修改。他们的系统选择最好的短语来使用,但在当前全球疫情的情况下,该公司认为最好避免某些短语,如“病毒式传播”
展望未来,随着我们的生活在疫情期间和之后继续进化,负责维护机器学习模型的计算机科学团队将需要继续做出这些改变。这样,我们正在经历的新世界将会在算法的行为中得到反映。
这也适用于新的机器学习模型的开发,这些模型是为了响应疫情而创建的。
随着新冠肺炎病毒带来的种种不确定性,科学家们一直在开发预测该病毒未来的算法。
在5 月 19 日发表的一项研究中,西奈山医院的研究人员将胸部 CT 扫描和患者数据与机器学习模型相结合,以诊断新冠肺炎患者。他们发现,在某些情况下,他们的算法在确定哪个病人感染了病毒方面甚至比高级胸科放射科医生还要好。
其他医院迫切希望了解哪些病人会病情危急,甚至已经开始使用尚未验证的算法。
机器学习也被用于预测病毒的传播,并确定隔离和社会距离等缓解措施的效果。
伦斯勒理工学院的研究人员将这些努力集中在单个城市。他们指出,较小的城市更难建模,因为训练算法的数据较少。在这些情况下,他们需要做出调整以做出准确的预测。
就像影响我们日常生活其他方面的算法一样,随着我们对病毒的了解越来越多,并适应新常态,这些模型也必须更新。
AI 的目的是让我们的生活更简单。机器学习模型在许多不同的行业中以许多不同的方式做到这一点。但是,随着这种相互联系,我们有必要共同成长。否则,他们就有被落下的危险。
新冠肺炎和机器学习
一种潜在的机器学习方法,可以帮助控制新冠肺炎
成功提交:【https://innovate.mygov.in/covid19/】

注: 注:我的方法将侧重于解决印度*(我的祖国)在评估新冠肺炎的影响时所面临的挑战。但是下面的方法很容易推广,因为其他受影响的国家也面临着与印度类似的挑战。*
此外,我通过考虑从高感染和受打击最严重的国家(如意大利、西班牙、英国、美国)以及在控制新冠肺炎疫情方面非常成功的国家(如韩国)获得的经验,制定了这个 ML 方法;中国-武汉,澳大利亚,阿联酋!
目录?
- 解决控制印度新冠肺炎病毒传播和死亡人数的主要问题/挑战&其他国家?
- 我提出的想法/解决方案
- ML 问题公式化&解决上述挑战的解决方案
- 一种潜在的 ML 方法/解决方案
- 这是长久之计吗?
1: 解决印度控制新冠肺炎病毒传播和死亡人数的主要问题/挑战&其他国家?
—问题是:
缺乏专注的测试!!!
1.1:为什么测试很重要
- 测试让受感染的人知道他们被感染了。这可以帮助他们接受所需的护理,也可以帮助他们采取措施降低感染他人的概率。不知道自己被感染的人可能不会呆在家里,从而有感染他人的风险。
- 测试对于适当应对疫情也至关重要。它让我们了解疾病的传播,并采取循证措施减缓疾病的传播。
- 不幸的是,在许多国家,包括印度和世界各地,新冠肺炎检测的能力仍然很低。由于这个原因,我们仍然没有很好地了解疫情的传播。
新冠肺炎考试如何进行: 这里
1.2:那么,测试阈值应该是多少呢?
为了找到这一点,我们需要理解可视化。我还在下面附上了整个 ipython 笔记本的链接。
数据来源:https://ourworldindata.org/

百万分之 2 Y 轴条形图
- 像 中、汉、韩、澳 这样的国家在拉平新冠肺炎传播曲线方面一直很繁荣,因为他们根据每百万人口增加了每百万人口的检测。
显然,从上面的可视化中,我们可以得出结论,为了控制新冠肺炎传播,(test _ per _ million≥population _ per _ million * 100)意味着 100 万人口需要至少 100 个测试容量。
像印度、美国、英国、西班牙和意大利这样的国家还没有达到上述检测标准,并且仍然在与新冠肺炎疫情做斗争,甚至还在与每百万人口检测做斗争。
1.3:对印度&其他国家来说,增加每百万人的检测数量有哪些挑战?还有为什么需要倍数?
- 印度&其他受影响的国家卫生资源有限。印度每万人拥有 8 名医生,而意大利和韩国分别为 41 名和 71 名。
- 疾病的早期(最初 1-3 天)病毒载量太低,无法检测。这会导致假阴性,因此需要多次测试/个体,最终导致每百万人的测试应至少大于或等于每百万人口的 100 倍,这一点我们可以从其他成功国家的数据中学习。
- 测试是一个手动过程,导致 处理&人为错误 。
为什么我们没有足够的新冠肺炎测试(详细): 这里
2:我提出的想法/解决方案
所以,如果问题是缺乏集中测试!!!那么新冠肺炎疫情的解决方案就是:
“测试测试测试&然后检疫”
但是,我已经提到,增加检测数量的挑战不是微不足道的,特别是当印度和其他国家,甚至美国、英国、意大利和伊朗,也有最少的卫生资源和同样的问题。
在计算机科学中,有一句流行的话:“最好的解决方案是最简单的!”。我们需要在很短的时间内增加每百万测试的数量,这里我提出了我对这个问题的想法/解决方案:
我们应该使用基于优先级的自动化测试系统(PbATS) 使用 ML/AI 来区分测试的优先级。这有助于确定测试的优先级,并有助于确定提供有限医疗服务的优先级。
使用 PbATS,我们将根据他们的输入对人群进行分类。为此,假设我们将人口分为以下三类:
类别 1(自我隔离):它们要么未受影响,要么仍未显示系统,但已受影响(假阴性)。它主要包含了未受影响的&一些假阴性病例。因此,他们需要定期接受 PbATS,直到特定的持续时间。
类别 2(测试优先级):该类别包含一些假阴性,但开始显示症状,因此需要手动测试
第 3 类 (医疗保健服务-优先):这一类由极有可能感染新冠肺炎病毒的人组成,因此,他们应该被严格隔离,并得到优先的医院服务。

PbATS 工作流程
注: 这种 PbATS 机制将是一种 AI/ML 方法,我们根据过去所有新冠肺炎患者的历史数据对这三个类别进行分类。众所周知,“所有的机器学习模型都是错误的,只有一些是有用的”——考虑到这一点,我的解决方案包含对类别 1 和类别 3 的多次尝试,因为类别 2 已经有了手动测试。
此外,在领域专家/新冠肺炎专家的帮助下,可以准确确定类别数量和周期。
3:解决上述挑战的 ML 问题公式和解决方案
现在,为了让上述解决方案发挥作用,我们需要鲁棒的 PbATS。现在,我将展示一种使用机器学习技术构建这种 PbATS 的潜在方法。
ML 问题公式化: 我们需要根据那里、特征(年龄、性别)、症状、过往旅行史对人群进行分类。
解决方案工作流程:一旦该 PbATS 准备就绪,每个人都需要通过数字方式或通过志愿者填写他们的详细信息(以最大限度地减少错误),然后医生可以轻松确定测试/医疗保健服务的优先级,并选择要隔离的人。这有助于医生和政府用最少的卫生资源阻止新冠肺炎。
最终,这种 PbATS 机制将间接帮助政府&医疗服务提供者增加test _ per _ million根据 人口 _per_million 阻止新冠肺炎传播所需的。
4:潜在的 ML 方法/解决方案
4.1:数据? 对于这一点,我已经取了数据,刮了数据(使用文本挖掘技术),并把它们串联起来。数据来源如下:
- https://ourworldindata.org/coronavirus
- https://www.kaggle.com/tags/covid19
- https://www . who . int/docs/default-source/corona virus/situation-reports/2020 03 23-sit rep-63-covid-19 . pdf?sfvrsn=d97cb6dd_2
下面是原始数据的样子:

原始数据样本
4.2:数据清理后:

数据清理
4.3:然后,我做了一些特色工程如下:
- 将年龄范围(60-65)转换为平均值(62.5)
- 增加了 日期 _ 过去 _ 发病 _ 症状(dpos) 这是天数 b/w 日期 _ 确认的差异&日期 _ 发病 _ 症状
- 基于 travel _ history _ dates&travel _ history _ locations 之间的操作,增加了travel _ history(th)标志
- 最后,将来自整个数据点的所有特征合并为一个 主症状/混合症状 。我这样做的原因稍后会更明显
4.4:最终数据集:

最终数据集
4.5:主症状上的自然语言处理
然后,我执行了所有标准的 NLP 技术来矢量化主症状。我用过BoW+W2V(word 2 vec-gensim)。我使用 W2V 是因为我需要根据关系(不是相似性&计数)*对症状进行聚类,这有助于聚类过程。*
我使用了 BoW,而不是 TF-IDF ,因为我们的数据集没有很多罕见的、出现的、需要更多重要性的单词。
4.6: ML 聚类:
最后,我用k means++做了聚类(最通用)。我们使用肘方法得到的聚类数也是 3(巧合的是),但是也可以使用更多的 领域知识 来改变它!
4.7:结果/词云:

基于 3 个聚类的主症状,dpos:过去发病天数-症状,th:旅行史
最终类别: 从上面主症的词云可以看出,我们可以大致将易发人群归类为:
第 3 类(医疗保健服务-优先):【年龄在 30-75 岁之间】+【发热、咳嗽、呼吸道感染、流鼻涕、喉咙痛、肺炎、头痛、胸闷(主要有dpos>4)+[th-1*经常旅行记录】*
第 2 类(测试优先):【年龄在 0-75 岁之间】+【发热、咳嗽、不适、肺炎、僵硬、关节、肌肉酸痛以及dpo 在 1-3 之间* ] + [ th-0/1 活动或不活动的旅行记录】*
第 1 类(自我隔离):【年龄在 0-75 岁之间】+【发热、咳嗽、虚弱、腹泻、头晕、寒战,dpos 在 1-3 之间】+[th-0*大部分无旅行史,也有一些有旅行史】*
学问: 我们可以看到,症状模式取决于 年龄, 主要以新冠肺炎为例,而变得严重的有dpos我的努力只是为了检测这些模式,以便优先使用 PbATS 进行测试。**
Jupyter 笔记本
类似实现:此处
5:这是永久的解决方案吗?
根本没有! 上述解决方案仅通过有限的医疗服务帮助印度和其他国家阻止新冠肺炎的传播。因此有助于遏制 Sars-CoV-2。
这种永久性的解决方案是 疫苗 ,需要数周甚至数月才能准备好。通过使用现有病毒疫苗(Sars-1,西班牙流感)等的组合找到疫苗,这种缺口也可以使用 ML/AI 容易地发现。,使用 ML/AI 技术。
****最后,是的,上述方法解决了医疗资源有限的问题。尽管如此,像印度和其他国家需要每百万人口中至少有 30%-40%的医疗资源(床位/呼吸机)用于第三类。
这个博客是我对在印度盛行的新冠肺炎 esp 战斗的一点微薄贡献。报送:https://innovate.mygov.in/covid19/
差不多就是这样!【bbhopalw@gmail.com】接:
PS:
- 关于数据集的请求——我已经把用 nodeJS 编写的 数据集& Web 抓取代码都开源了,可以在我的 GitHub 上获得。
- 关于 合作 ,请直接发邮件给我。
- 这是博客原文。读者可能会在其他数据科学 简讯(upGrad,DS news) 中找到这一点(再版!).

再版—时事通讯
连接 🤝 :
- 邮箱:bbhopalw @ Gmail
- Linkedin:www.linkedin.com/in/bbhoaplw
延伸阅读✍️:****
大数据&云工程博客:
后端工程&软件工程博客:
基于新冠肺炎机器学习的普通实验室检查快速诊断
塔尔西斯·苏扎博士、古斯塔沃·文泽尔·塞纳托医学博士和赫利·苏扎医学博士
来自巴西 5644 名患者的证据

摘要
- 新冠肺炎病例的突然快速增长正在使全球卫生系统不堪重负。快速、准确和早期检测新型冠状病毒对控制病毒传播至关重要。然而,基于 RT-PCR 分析的传统新型冠状病毒检测可能成本高、耗时长且普遍不可用,使得检测每个病例成为不切实际的努力。
- 我们提出了一种基于机器学习的方法,使用通常可用的实验室测试数据来快速检测新冠肺炎病例。
- 我们分析了巴西圣保罗的以色列阿尔伯特爱因斯坦医院的 5644 名患者样本,其中 558 名患者的新型冠状病毒检测呈阳性。考虑到原始样本数据的⅓的保留测试组,所提出的模型呈现出 92% (AUC)的总体高性能。
- 我们观察到,有新冠肺炎症状且鼻病毒、肠病毒、B 型流感和 Inf 检测呈阴性的患者。2009 年甲型 H1N1 流感,白细胞和血小板水平较低,更有可能检测出新型冠状病毒阳性。
- 我们提出了一个基于不同场景的参数模型,这些场景是作为目标敏感度水平或医院有能力优先处理的潜在阳性病例总数的函数给出的。
- 在 25%的患者被认为是新型冠状病毒阳性的情况下,所提出的模型显示出分别超过 84%和 96%的灵敏度和特异性,因此被证明是一种有用的快速优先化工具。
介绍
背景
世界卫生组织(世卫组织)在 3 月 11 日将由新型冠状病毒引起的新冠肺炎定性为疫情,而病例数量的指数级增长有可能使世界各地的卫生系统不堪重负,对 ICU 床位的需求远远超过现有能力,意大利的一些地区就是突出的例子。

巴西于 2 月 26 日记录了第一例新型冠状病毒,病毒传播从仅输入病例发展到当地并最终社区传播非常迅速,联邦政府于 3 月 20 日宣布全国社区传播。
截至 2020 年 3 月 27 日,圣保罗州记录了 1223 例新冠肺炎确诊病例,68 例相关死亡,而截至 3 月 23 日,拥有约 1200 万人口和以色列阿尔伯特·爱因斯坦医院所在地的圣保罗州有 477 例确诊病例和 30 例相关死亡。该州和圣保罗县都决定建立隔离和社会距离措施,这将至少持续到 4 月初,以努力减缓病毒的传播。
动机和目标
这项工作的目标是根据通常收集的实验室检查结果预测疑似病例中的确诊新冠肺炎病例。我们考虑以下研究问题:
根据在急诊室就诊期间通常为疑似新冠肺炎病例收集的实验室检测结果,是否有可能预测 SARS-Cov-2 的检测结果(阳性/阴性)?
这项工作的一个动机是,在卫生系统不堪重负的情况下,对新型冠状病毒的检测进行测试可能会受到限制,测试每个病例是不切实际的,考虑到测试结果需要 48 小时到一整周的时间,即使只测试一个目标亚群,测试也可能会被推迟。
贡献
我们提出了一个简单的模型来快速预测感染新型冠状病毒病毒风险最高的患者,使他们能够得到优先考虑,并有可能采取隔离措施和相关的医疗程序。我们的贡献有三个方面:
- 新型冠状病毒的快速高准确度测试:提议的模型仅基于通常可获得的实验室测试数据,其表现出 92%的 AUC 和大于 85%的灵敏度水平以及大于 85%的合理特异性水平的高性能
- 可解释性:变量的重要性和与结果变量的条件依赖性很容易从模型中提取出来,其解释可以指导医疗决策
- 灵活性:根据目标敏感度水平、医院能力和疾病流行程度,模型构建可灵活适应不同的政策情景
资料组
该数据集包含在巴西圣保罗的以色列阿尔伯特爱因斯坦医院就诊的患者的匿名数据,这些患者在就诊期间收集了样本以进行新型冠状病毒 RT-PCR 和其他实验室测试。

巴西圣保罗的阿尔伯特·爱因斯坦医院收集并提供了该数据集。
所有数据都按照最佳国际惯例和建议进行了匿名处理。所有的临床数据被标准化为平均值为零和单位标准差。
该数据集包含 109 个变量(预测因子),一个患者 ID 和一个目标结果变量,该变量指示患者是否对 SARS-Cov-2 检测为阳性/阴性。有 5644 个样本可用,其中有 558 个阳性病例,占数据集的 10%。
数据准备
首先,我们执行一些基本的数据清理程序:
- 通过删除特殊字符、空格和符号,使变量名在语法上有效
- 将表示缺失数据的字符串转换为 NA ,即以下值:“no realization do”和“not_done”
- 将字符串分类值转换为因子
- 将变量尿…pH 转换为数值,因为它在输入数据中包含字符串和数值的混合
我们的结果变量被命名为 SARS。Cov.2.exam.result ,它是一个二元变量,表示患者对 SARS-COV2 病毒的检测是阳性还是阴性。我们将此变量转换为\(SARS。Cov.2.exam.result = 1\),如果患者检测为阳性,则为\(SARS。Cov.2.exam.result = 0\),否则。
如下所示,大多数变量都有很高的缺失值百分比(NA)。这里的问题是,在我们提出的预测建模中,当数据被分成交叉验证/自举子样本时,这些预测器可能成为零方差预测器。

因此,我们去除了有太多缺失数据点(> = 95%)的变量。我们还去除了实验室数据中过于稀疏的样本,我们选择保留至少有 10 个变量和数据点的阴性样本。这样做是为了避免过拟合的情况,在过拟合的情况下,少数样本(稀疏但正的)可能会对预测模型产生不适当的影响。
删除了以下变量:
[1] "Serum.Glucose" [2] "Mycoplasma.pneumoniae" [3] "Alanine.transaminase" [4] "Aspartate.transaminase" [5] "Gamma.glutamyltransferase." [6] "Total.Bilirubin" [7] "Direct.Bilirubin" [8] "Indirect.Bilirubin" [9] "Alkaline.phosphatase" [10] "Ionized.calcium." [11] "Magnesium" [12] "pCO2..venous.blood.gas.analysis." [13] "Hb.saturation..venous.blood.gas.analysis." [14] "Base.excess..venous.blood.gas.analysis." [15] "pO2..venous.blood.gas.analysis." [16] "Fio2..venous.blood.gas.analysis." [17] "Total.CO2..venous.blood.gas.analysis." [18] "pH..venous.blood.gas.analysis." [19] "HCO3..venous.blood.gas.analysis." [20] "Rods.." [21] "Segmented" [22] "Promyelocytes" [23] "Metamyelocytes" [24] "Myelocytes" [25] "Myeloblasts" [26] "Urine...Esterase" [27] "Urine...Aspect" [28] "Urine...pH" [29] "Urine...Hemoglobin" [30] "Urine...Bile.pigments" [31] "Urine...Ketone.Bodies" [32] "Urine...Nitrite" [33] "Urine...Density" [34] "Urine...Urobilinogen" [35] "Urine...Protein" [36] "Urine...Sugar" [37] "Urine...Leukocytes" [38] "Urine...Crystals" [39] "Urine...Red.blood.cells" [40] "Urine...Hyaline.cylinders" [41] "Urine...Granular.cylinders" [42] "Urine...Yeasts" [43] "Urine...Color" [44] "Partial.thromboplastin.time..PTT.." [45] "Relationship..Patient.Normal." [46] "International.normalized.ratio..INR." [47] "Lactic.Dehydrogenase" [48] "Prothrombin.time..PT...Activity" [49] "Vitamin.B12" [50] "Creatine.phosphokinase..CPK.." [51] "Ferritin" [52] "Arterial.Lactic.Acid" [53] "Lipase.dosage" [54] "D.Dimer" [55] "Albumin" [56] "Hb.saturation..arterial.blood.gases." [57] "pCO2..arterial.blood.gas.analysis." [58] "Base.excess..arterial.blood.gas.analysis." [59] "pH..arterial.blood.gas.analysis." [60] "Total.CO2..arterial.blood.gas.analysis." [61] "HCO3..arterial.blood.gas.analysis." [62] "pO2..arterial.blood.gas.analysis." [63] "Arteiral.Fio2" [64] "Phosphor" [65] "ctO2..arterial.blood.gas.analysis."
其余的变量如下:
[1] "Patient.age.quantile" [2] "SARS.Cov.2.exam.result" [3] "Patient.addmited.to.regular.ward..1.yes..0.no." [4] "Patient.addmited.to.semi.intensive.unit..1.yes..0.no." [5] "Patient.addmited.to.intensive.care.unit..1.yes..0.no." [6] "Hematocrit" [7] "Hemoglobin" [8] "Platelets" [9] "Mean.platelet.volume" [10] "Red.blood.Cells" [11] "Lymphocytes" [12] "Mean.corpuscular.hemoglobin.concentration..MCHC." [13] "Leukocytes" [14] "Basophils" [15] "Mean.corpuscular.hemoglobin..MCH." [16] "Eosinophils" [17] "Mean.corpuscular.volume..MCV." [18] "Monocytes" [19] "Red.blood.cell.distribution.width..RDW." [20] "Respiratory.Syncytial.Virus" [21] "Influenza.A" [22] "Influenza.B" [23] "Parainfluenza.1" [24] "CoronavirusNL63" [25] "Rhinovirus.Enterovirus" [26] "Coronavirus.HKU1" [27] "Parainfluenza.3" [28] "Chlamydophila.pneumoniae" [29] "Adenovirus" [30] "Parainfluenza.4" [31] "Coronavirus229E" [32] "CoronavirusOC43" [33] "Inf.A.H1N1.2009" [34] "Bordetella.pertussis" [35] "Metapneumovirus" [36] "Parainfluenza.2" [37] "Neutrophils" [38] "Urea" [39] "Proteina.C.reativa.mg.dL" [40] "Creatinine" [41] "Potassium" [42] "Sodium" [43] "Influenza.B..rapid.test" [44] "Influenza.A..rapid.test" [45] "Strepto.A"
预测分析
模特培训
为了预测患者感染 SARS-Cov2 病毒的可能性,我们将数据集随机分为训练和测试测试,训练与测试的分割比为 2/3。我们分解数据集,使得结果变量也遵循训练集和测试集之间的相同分割比。
我们使用剩余的数据集变量作为预测器来训练 GBM 模型。我们还定义了一个袋分数,它定义了随机选择的训练集观察值的分数,以提出扩展中的下一棵树。这将随机性引入模型拟合,并减少过度拟合。
模型可解释性
我们通过观察变量的相对重要性以及它们相对于结果变量的条件依赖概率来评估模型的可解释性。模型解释是重要的,因为它们可以用来改善医疗决策和指导政策制定的倡议。
模型返回的前 10 个最重要的变量如下所示。重要性度量是标准化的,它们基于变量被选择用于树分裂的次数,由作为每个分裂的结果的模型的改进来加权,并在所有树上平均。

我们分析了下面 5 个最重要变量的条件概率图,其中 x 轴代表预测值,y 轴代表感染的可能性(数字是归一化的)。我们观察到以下情况:
- 当鼻病毒。肠病毒,流感。b 或 Inf。甲型 H1N1.2009 未被检测到,患者更有可能检测出 SARS-COV2 阳性
- 白细胞或血小板低的患者更有可能检测出 SARS-COV2 阳性





作为严重新冠肺炎病例的主要指标,一个被广泛讨论的变量是年龄。因此,我们分析变量 age_quantile 和之前讨论的前 5 个最重要的变量之间的二元关系。我们观察到,当与研究的其他前 5 个变量结合时,患者的年龄分位数可以增加 SARS-COV2 感染的可能性。





预测
我们将训练好的模型应用于 668 名患者的测试数据集。我们观察到该模型表现非常好,AUC 为 92%。然而,模型的特异性和敏感性的确定依赖于可能性阈值的定义,以确定在疑似病例中被认为可能是阳性新冠肺炎病例的患者。

下面我们可以看到阈值的选择如何影响模型的灵敏度和特异性(使用训练集的样本内分析)。具有高灵敏度的模型在那些真正的阳性患者中找到阳性患者方面取得了良好的结果。然而,预测为阳性的患者数量可能过高,并影响模型的特异性。此外,如果这个数字太高,医院可能没有足够的资源来为所有被分配了阳性标签的患者应用必要的程序。因此,理想的模型是平衡良好的模型,即,具有高灵敏度但不会给患者过多分配阳性标记的模型。

为了确定选择哪种可能性以及如何确定哪些患者更有可能被感染,我们讨论了与不同的医院、城市、州或国家特定政策相关的不同场景。对于每个场景,我们将从训练集中选择阈值,该阈值优化由场景中的策略驱动的给定目标函数。
场景 1:资源的高可用性
在场景 1 中,我们假设医院具有高可用性的资源。这样,模型就可以放松,高估阳性病例的数量。因此,我们的目标函数是使灵敏度最大化。
我们使用训练数据来选择最大化模型灵敏度的阈值。然后,我们将这个阈值应用于测试集中的预测概率。该过程返回 1.6%的概率阈值,并且该模型呈现 95%的高灵敏度值,如预期的那样。然而,高召回率是以特异性为代价的,特异性呈现 34%的低值。此外,测试集中约 74%的患者被标记为阳性,因此该模型作为优先化工具的使用有限。
场景 2:资源有限
在场景 2 中,我们假设环境资源有限,因此,如果我们能够获得一个平衡的模型,那么降低模型的敏感度是可以接受的。为此,我们选择最大化定义为\(max(灵敏度+特异性)\)的约登 J 统计量作为目标函数。
下面,我们可以看到阈值对相应的约登 J 统计值的影响(样本内分析)。我们观察到,过低或过高的阈值会导致模型中的次优平衡。
在对测试集进行预测后,我们将从训练集中选择一个阈值,该阈值最大化约登 J 统计量,以实现良好平衡的模型。我们观察到,与场景 1 的 95%相比,场景 2 下的模型现在提供了 84%的灵敏度。然而,它返回 96%的特异性,同时保持 92%的高 AUC(因为阈值的选择不影响 AUC),因此提供了预期的更好平衡的模型。此外,现在该模型仅将 26%的测试集分配给阳性标签,显示出作为潜在的患者优先化工具是有用的。

场景 3:有限的资源,不同的政策
在情景 3 中,我们假设不同的医院可能对敏感度的可接受值有不同的政策,或有不同的能力检测优先患者,以及有不同的流行水平。因此,我们通过提出一个具有成本函数的参数模型来概括场景 1 和 2 下研究的模型,该成本函数允许医生根据目标策略以及作为输入参数的输入流行度,与假阳性分类相比,高估或低估假阴性分类。
我们的目标函数是
\(max(灵敏度+r * specific)\),
在哪里
\(r = 1 —流行率/成本*流行率\)
并且\(r\)是假阴性分类的相对成本(与假阳性分类相比)。不同的国家和地区可能有不同的流行率,而不同的医院可能有不同的政策来定义\(cost\)参数。
我们的研究结果表明,在标记为阳性的患者百分比数($num . positive . pct $)低于 30%的情况下,可以提供特异性和敏感性均大于 85%的实用模型,因此可以作为相关的优先化工具。此外,该模型被参数化,以允许容易地微调,从而针对目标敏感度、患病率或要优先考虑的患者的最大数量进行调整。


实际应用
在实践中,使用建议模型的卫生工作者/医院将为最低可接受敏感度水平或要优先考虑的患者目标数量定义政策,并指定当前流行率。这些参数将作为模型的输入,以确定可能检测为阳性的优先患者。然后,该模型将输出新型冠状病毒感染、可能性测量和准确性的二元指标。该模型的输出可用作优先化的工具,并支持进一步的医疗决策过程。输入参数和医院的政策可以根据卫生系统的状况定期更新。然后,该模型将被重新训练,并纳入新的可用数据。
结论
在这项工作中,我们通过分析来自以色列阿尔伯特·爱因斯坦医院的 5644 名患者(其中 558 名患者的新型冠状病毒病毒检测呈阳性)的样本,表明可以根据通常为疑似新冠肺炎病例收集的实验室检测结果来预测新型冠状病毒的检测结果。
根据目标政策/方案,所提出的模型具有 92%的 AUC 和大于 85%的敏感性/特异性水平的实际应用。该模型具有较高的可解释性,进一步显示了鼻病毒、肠病毒、B 型流感和 Inf 检测阴性的新冠肺炎症状患者。2009 年甲型 H1N1 流感,白细胞和血小板水平较低,更有可能检测出新型冠状病毒阳性。
我们还研究了如何根据不同的场景来调整模型的性能,这些场景被定义为目标敏感度的函数或医院对大量患者进行优先排序的政策。我们发现,如果医院愿意考虑选择 75%的患者进行检测,特异性水平可以达到 98%以上。然而,我们表明,在患者优先级别约为 25%的情况下,可以实现良好平衡的模型(特异性和敏感性均大于 85%),因此证明这是一个相关的优先程序。模型的性能平衡可定义为考虑患病率、患者优先级别或目标敏感度级别的医院特定政策的函数。
我们采用了一种简约的建模方法,并构建了一个简单有效且透明的基线模型。我们承认,由于研究中的几个限制因素,应该谨慎对待这些发现,这些限制因素包括:(1)数据样本数量少;㈡不平衡的数据集;(iii)预测值的高度稀疏性。此外,该数据集具有潜在偏见,即在本研究中研究的特定医院的普通实验室检测中存在病毒筛查,这可能在巴西或世界范围内的许多其他医疗机构中不可用。
进一步的研究应该通过考虑生命体征和体检记录来解决变量的稀疏性。鉴于这种疾病的概况,来自 x 射线和断层扫描的图像研究可以提供严重病例的早期检测,预测是否需要 ICU 病床。
数据和代码可用性声明
这项工作报告了由巴西圣保罗的以色列阿尔伯特爱因斯坦医院创建的 Kaggle 数据集诊断新冠肺炎及其临床谱的结果。
完整代码可在 https://github.com/souzatharsis/covid-19-ML-Lab-Test获得
用 Python 在 5 分钟内创建新冠肺炎地图动画
数据可视化
用 Python 和 Plotly 制作新冠肺炎地图动画

马特·拉默斯在 Unsplash 上拍摄的照片
在抗击新冠肺炎的战斗中,GIS 技术在很多方面都发挥了重要作用,包括数据整合、疫情信息的地理空间可视化、确诊病例的空间追踪、区域传播预测等等。这些为政府部门抗击新冠肺炎疫情提供了支持信息。[1]为了解决这个问题,JHU 提供了一个用 ESRI ArcGIS operation dashboard 创建的漂亮的仪表盘:

CSSE 在 JHU 的 新冠肺炎仪表盘(2020 年 5 月 29 日截图)
仪表板提供了累计确诊病例总数、活跃病例、发病率、病死率、检测率和住院率的非常好的概览。但是,在地图上可视化数据随时间变化的功能丢失了!
本文将向您介绍一种使用 JHU·新冠肺炎数据集创建可视化新冠肺炎随时间扩展的动态地图的简单方法。
我们开始吧!
步骤 1:准备 Python 库
我们将在本文中使用的 Python 库主要是 Pandas、PyCountry 和 Plotly Express。你们中的大多数人可能已经知道 Plotly 库,但是如果不知道,你可以在这篇文章中查看它的所有特性。
**$ pip install pandas
$ pip install pycountry
$ pip install plotly**
步骤 2:加载数据集
我们将在这里使用的数据集是 JHU·CSSE·新冠肺炎数据集。你可以从 CSSE Github repo 下载或获取它的最新更新版本。您可以查看这篇文章,了解如何使用 PythonGit 在您的 Python 项目中随时间自动更新数据源。在本文中,我们将只关注**time_series_covid19_confirmed_global.csv** 数据集。

来自 JHU CSSE 的时间序列 _ covid 19 _ confirmed _ global . CSV
然后,您可以使用以下命令轻松地将数据加载到 dataframe
**import pandas as pd
df_confirm =** **pd.read_csv('path_to_file')**

****时间序列 _ covid19 _ 已确认 _ 全局数据集
步骤 3:清理数据集
为了使用 Plotly Express 动态可视化时间序列数据集,您需要满足以下数据框架要求。
- ****将数据集聚合到国家级别。
- ****获取每个国家在ISO 3166–1中定义的三个字母的国家代码;例如,
AFG代表阿富汗。你可以使用 PyCountry 来做到这一点。 - ****将数据集转换为长格式,其中日期值在单个列中表示。您可以轻松完成此操作,首先将数据集加载到 Pandas 数据帧中,然后在 Pandas 中使用 melt 。
您可以使用此 Python 脚本执行以下步骤:
总体而言,最终的干净数据帧如下图所示:

****已清理的时间序列 _ covid19 _ 已确认 _ 全局数据集
步骤 4:使用 Plotly Express 创建地图动画
数据集准备就绪后,您可以使用 Plotly Express 轻松创建地图动画。例如,您可以使用下面的脚本从步骤 3 的数据帧创建一个动画 choropleth 图,您也可以根据自己的喜好调整每个参数。
使用 Plotly Express 从 time _ series _ covid 19 _ confirmed _ global 数据集创建动画 choropleth 的 Python 脚本

使用 Plotly Express 从时间序列 _ covid19 _ 已确认 _ 全局数据集制作的动画 choropleth】
差不多就是这样!简单对吗?
下一步是什么?
此示例可视化了已确认的新冠肺炎病例数据集,但您也可以尝试将此方法应用于可视化新冠肺炎死亡病例和康复病例数据集。
关于用 plotly 绘制动画 choropleth 地图的更多信息,查看完整文档这里。如果你想改变色阶,你可以简单地从这里选择内置色阶。应用更好的颜色符号规则。尝试创建其他类型的地图,如散点图或热图,通过查看 Plotly 地图库这里。
或者,您可以通过本文查看如何在 Kepler.gl 中可视化新冠肺炎数据,这是一个用于动态数据可视化的地理空间分析工具。
结论
本文将向您介绍如何使用 Plotly Express 以简单的方式准备数据集和创建地图动画。我希望你喜欢这篇文章,并发现它对你的日常工作或项目有用。如果您有任何问题或意见,请随时给我留言。
关于我&查看我所有的博客内容:链接
安全健康和健康!💪
感谢您的阅读。📚
参考
[1]周,陈,苏,李,李,马,蒋,李,阎,李,易,胡,杨,肖,(2020)。新冠肺炎:大数据对 GIS 的挑战。地理和可持续性,1(1),77–87。https://doi.org/10.1016/j.geosus.2020.03.005
使用 ELK 构建新冠肺炎地图
变更数据
使用 elasticsearch 创建您自己的自定义新冠肺炎地图

新冠肺炎麋鹿地图,可在https://covid 19 Map . uah . es/app/dashboards #/view/478 e9 b 90-71e 1-11ea-8d D8-e 1599462 e 413|图片由作者提供
可能你们大多数人都熟悉约翰·霍普金斯大学(JHU)的地图代表新冠肺炎疫情的现状。

约翰·霍普金斯大学(JHU)地图的图像(约翰·霍普金斯大学)
这张地图是使用 ArcGIS 技术开发的,在很多情况下,这已经成为开发疫情地图的事实上的标准,例如世卫组织政府的地图。
在看到这个之后,我想用麋鹿创建我自己的地图;几天后,在一个朋友的帮助下,一切都运转起来了。根据我的经验,我决定写你如何也能轻松做到这一点。这一系列的文章将集中在如何使用 ELK 栈创建你自己的自定义地图。
为什么选择 Elasticsearch?
第一个要回答的问题是为什么是麋鹿?而不是使用 ArcGIS 技术。Elasticsearch 是开源的,每个人都可以轻松部署一个正在运行的集群。此外,Elasticsearch 使用 Kibana 进行了漂亮的展示,并且还提供了地图,因此它拥有我们构建令人难以置信的新冠肺炎地图所需的一切。我真的很喜欢麋鹿栈,所以我决定尝试一下。
我在一个月 10 美元的数字海洋 VPS 中运行了 ELK stack,显然没有冗余和大量空间,但我们会发现我们不需要大量空间来存储数据。
基于这一点,我们的成本将只是运行 ELK 的基础设施,但一个小的 VPS 可以运行一个小的集群。我没有很多闲钱,所以我总是试图将成本保持在最低水平。我已经运行了 ELK stack,每月 10 美元数字海洋 VPS ,显然没有冗余和大量空间,但我们会发现我们不需要大量空间来存储数据。另一种选择是使用弹性云。

我当前部署的弹性云|图片作者
弹性云是运行 ELK 集群最简单的方式,并提供许多有用的功能。例如,ELK 的一个问题是频繁更新新功能的数量。在 Elastic Cloud 中,更新集群就像按下控制面板中的一个按钮一样简单。此外,最小的部署成本低于每月 20 美元。就我而言,我停止使用弹性云是因为它的易用性和易于管理。我完全推荐这个选项,不要忘记你有 14 天的试用期。
新冠肺炎数据来源
同意 ELK 堆栈的惊人之处后,我们可以开始考虑如何在 ELK 中插入新冠肺炎数据。首先,我们为地图确定一个可靠和更新的数据源。我们需要每天检索和插入新数据来更新我们的地图。
约翰霍普金斯大学(JHU) 在 GitHub 上发布他们的数据。它们都是 CSV 格式,可以很容易地使用。新冠肺炎意大利数据也发生了类似的事情。这种格式可以很容易地被解析和插入,但是有几个问题。在解析这些数据的过程中,我遇到了几个问题。第一个是数据更新过程,例如,JHU 并不总是更新数据最快的。这很正常,他们需要等待新数据的发布,并将其纳入数据集中。您将看到意大利知识库更新更加频繁。
如果你计划运行一个更新的地图,最好的选择是不要使用那些 Github 库。
最好的选择是使用新冠肺炎 API。我们有几个选择,但我决定使用新冠肺炎叙事 API。
另一个问题是文件结构的变化。有时 CSV 结构已经改变,然后您需要再次解析这些文件,可以重命名列或者改变顺序。因此,如果你计划运行一个更新的地图,最好的选择是不要使用 Github 库。
为了避免这些问题,最好的选择是使用新冠肺炎 API。我们有几个选项,但我决定使用新冠肺炎叙事 API 。
要检索 2020 年 9 月 3 日的新冠肺炎数据,我们只需向 https://api.covid19tracking.narrativa.com/api/2020–09–03 的发出请求。在执行该请求后,我们将获得一个 JSON 响应,避免前面提到的所有问题。叙事瓦已经从几个官方数据来源检查和下载新冠肺炎信息:

新冠肺炎叙事 API |图片由作者提供
使用这个 API,我们可以检索我们需要的所有数据。从世界数据到国家和地区数据。API 的完整文档可以在这里找到。到了这一步,我们可以开始在 Elasticsearch 中消费和插入数据。
在松紧带内插入新冠肺炎
为了使用来自 API 的数据,我们可以使用 Logstash。Logstash 是在插入 Elasticsearch 之前收集、解析和转换信息的标准工具。此外,Logstash 已经为普通日志发布了许多预配置配置。
但是也有其他的可能性,比如 Python。我真的很喜欢 Python 语法和编程,所以当我从一个 API 消费时,我通常会结束构建一个脚本来消费数据并插入到 Elasticsearch 中。就像我说的,你可以用 Logstash 来做这件事,但是我觉得用 Python 编程更舒服。
所以还是从代码开始吧!!首先,我们需要从疫情开始到今天的所有数据。此外,我们希望将这些数据按日期分开,以便从不同的时间段过滤或创建可视化效果。使用 Python 请求和 datetime,我们可以轻松地迭代抛出所有日期并检索所有数据。我个人更喜欢的请求而不是的 urrlib ,我觉得它简单优雅得多。
使用 Python 请求和 datetime,我们可以轻松地迭代抛出所有日期并检索所有数据。
import requests
from datetime import datetime, date, timedeltastart_date = date(2020, 3, 1)
end_date = date(2020, 4, 9)
delta = timedelta(days=1)while start_date <= end_date:
day = start_date.strftime("%Y-%m-%d")
print ("Downloading " + day)
url = "https://api.covid19tracking.narrativa.com/api/" + day
r = requests.get(url)
data = r.json()
start_date += delta
获得每个日期的数据后,我们可以将它插入到 Elasticsearch 中,但在此之前,有必要对数据进行一些格式化。我们将在一个弹性地图中表示与国家相关的数据。为了将数据与每个国家相关联,elasticsearch 需要识别国家/地区的名称。叙事 API 为我们提供了英语、意大利语和西班牙语的名称,但有些国家的名称可能会有问题。因此,发明了 ISO 3166-1α-2(iso 2)和 ISO 3166-1α-3(iso 3)。使用这种命名法,我们可以很容易地识别每个国家的名字,不会出错。Python 有一个包 countryinfo 可以帮助我们将国家名称翻译成 iso3 格式。
Python 有一个包 countryinfo 可以帮助我们将国家名称翻译成 iso3 格式。
你需要比较人群的感染率,或者使用统计学指标,而不是绝对数字。这个主题在我完全推荐的 ArcGis 帖子中有详细介绍。
from countryinfo import CountryInfofor day in data['dates']:
for country in data['dates'][day]['countries']:
try:
country_info = CountryInfo(country)
country_iso_3 = country_info.iso(3)
population = country_info.population()
except Exception as e:
print("Error with " + country)
country_iso_3 = country
population = None
infection_rate=0
print(e)
另外,如果你检查了代码,可能大多数人都会看到一个人口值。不幸的是,Elasticsearch 现在不包括每个国家的人口数值,他们正在做那个。为了代表性地绘制新冠肺炎疫情,有必要获得每个国家的人口值,仅具有数量的热图是不具有代表性的。你需要比较感染率和人口数量,或者使用统计指标,而不是绝对数字。我强烈推荐的一篇 ArcGis 帖子中详细介绍了这个主题。
获得每个国家受感染人数代表性指标的一个简单方法是使用感染率。感染率代表人群感染的概率或风险。

感染率公式|作者图片
再次使用 Python,我们可以很容易地计算出这个数字。不幸的是,Python countryinfo 不包括所有国家的人口,因此我控制了这个例外。大多数国家都得到支持,但我发现了一些错误,如巴哈马群岛、Cabo 和其他一些国家。
def getInfectionRate(confirmed, population):
infectionRate = 100 * (confirmed / population)
return float(infectionRate)if population != None:
try:
infection_rate=getInfectionRate(data['dates'][day]['countries'][country]['today_confirmed'], population)
print(infection_rate)
except:
infection_rate=0
我用日期时间格式日期替换了时间戳。这样,Elasticsearch 将自动检测日期格式,而您将忘记创建 Kibana 索引。
完成所有这些修改后,我们只需要将这些数据插入到 Elasticsearch 中。在插入数据之前,我倾向于创建一个包含所有数据的自定义字典。我添加了以前的数据,人口,国家 iso3 名称,感染率,并用日期时间格式日期替换了时间戳。这样,Elasticsearch 将自动检测日期格式,而您将忘记创建 Kibana 索引。
def save_elasticsearch_es(index, result_data):
es = Elasticsearch(hosts="") #Your auth info
es.indices.create(
index=index,
ignore=400 # ignore 400 already exists code
)
id_case = str(result_data['timestamp'].strftime("%d-%m-%Y")) + \
'-'+result_data['name']
es.update(index=index, id=id_case, body {'doc':result_data,'doc_as_upsert':True}) result_data = data['dates'][day]['countries'][country]
del result_data['regions']
result_data['timestamp'] = result_data.pop('date')result_data.update(
timestamp=datetime.strptime(day, "%Y-%m-%d"),
country_iso_3=country_iso_3,
population=population,
infection_rate=infection_rate,
)save_elasticsearch_es('covid-19-live-global',result_data)
完整的脚本可以在 GitHub 上找到,只要记得在运行脚本之前添加你的 elasticsearch 主机,并安装所有的依赖项。
使用 Kibana 创建新冠肺炎可视化
Kibana 将自动识别时间戳字段作为时间过滤器,你只需要选择它。
运行该脚本后,将在 elasticsearch 中创建一个索引,您可以从 Kibana 配置它。Kibana 将自动识别时间戳字段作为时间过滤器,你只需要选择它。

基巴纳指数模式|图片由作者提供
数据表可视化
我们可以做的最简单的可视化之一是一个简单的表格,显示新冠肺炎病例最多的国家。

基巴纳表格显示新冠肺炎病例数最多的国家|图片由作者提供
为了创建这个可视化,我们需要一个数据表可视化。第一列可以是确诊病例的总数,使用 today_confirmed 上的简单 max 聚合,我们可以获得该数字。

Kibana 中的确诊病例总数配置|作者提供的图片
另一个有趣的指标可能是过去 48 小时内的最后确诊病例。人们可能会认为 24 小时的数字可能更有意义,但许多国家花了更多的时间来报告它们的病例,有了 48 小时的窗口,你将能够代表更多的结果。为了在 Kibana 中执行这种表示,我们需要一个 Sum Bucket 聚合。使用这种聚合,我们可以使用过去 48 小时的日期范围,现在-2d,然后再次使用最大聚合获得确诊病例数。

基巴纳最近 48 小时确诊病例配置|图片由作者提供
有了我们的聚合之后,我们唯一需要做的事情就是使用国家名称来拆分行。选择“按名称.关键字分割”将会这样做。此外,我会建议设置一个大小限制,我们将看到最重要的数字。在我的仪表板中,25 个降序数字似乎就足够了,但是您可以根据自己的喜好调整这个数字。

按国家名称拆分行|按作者拆分图片
新冠肺炎疫情地图可视化
我们能创造的最不可思议的可视化或者至少是最受欢迎的是一张显示新冠肺炎疫情演变的地图。Kibana 提供了几个创建地图的选项,在本例中,我们将选择 choropleth 选项。使用此选项,我们可以选择一个单词国家层,并选择 ISO 3166–1 alpha-3 作为格式,请记住我们是如何将它包含在脚本中的。统计源将是我们的索引名,包含 ISO 3166-1 alpha-3 的字段将是我们的连接字段,在我们的例子中是 country_iso_3。
还有,要意识到这一点!!,如果添加图层后地图仍然是黑色的,请检查您的基巴纳日期过滤器,并将最近 15 分钟选择器更改为最近 1 年。我花了很多时间思考我做错了什么,问题出在基巴纳时间选择器上。

Kibana 地图 choropleth 配置以在作者的地图|图像中创建一个图层
添加这一层后,我们还没有完成,所有国家都呈现相同的数据。我们需要选择 infection_rate 变量作为度量,以便根据其值绘制颜色,然后选择“按值填充颜色”,并再次选择 infection_rate。此外,我们可以在图层样式下的几个调色板中选择,我更喜欢红色调的那个。到达这一点,地图上应该有一些颜色。还有,要意识到这一点!!,如果添加图层后地图仍然是黑色的,请检查您的基巴纳日期过滤器,并将最近 15 分钟选择器更改为最近 1 年。我花了很多时间思考我做错了什么,问题出在基巴纳时间选择器上。

基巴纳地图 choropleth 图层配置|图片由作者提供
选择这些选项后,您应该能够看到如下内容:

基巴纳地图创作|作者图片
结论
希望通过本文提供的代码和示例,您能够创建自己的自定义地图和可视化。在这篇文章中有很多可能的基巴纳可视化,我只提出了一些想法。我的建议是尽可能多地尝试 Kibana 可视化。Kibana 是一个不可思议的工具,只需点击几下,你就可以创建以你的国家、地区或大陆为中心的图表。
新冠肺炎开源仪表板
作为数据科学家,我们必须尽最大努力从数据角度接近当前的新冠肺炎疫情。因此,我使用开源工具创建了一个仪表板来跟踪和可视化新冠肺炎的传播。
几周来,新冠肺炎疫情一直是一个不可回避的话题。媒体用新感染名人的突发新闻淹没了我们,几个国家的病例和死亡人数呈指数增长。如今,人们在社交媒体上无法谈论其他任何事情,卫生纸囤积者的视频在网上疯传。
公司没有错过这一趋势。在过去的几天里,我的 Twitter 和 LinkedIn 上充斥着各种公司,展示他们的技术有多棒,以及他们如何无私地利用它来支持政府机构、医疗保健机构等。不要误解我,我认为公司愿意提供帮助是很棒的;在当前的危机中,向任何需要帮助的公共机构提供援助的每一家公司都值得称赞!然而,如果这些贡献中的每一个都必须在营销方面得到充分利用,它们会留下一种陈腐的味道。
此外,最受欢迎的仪表盘使用了鼓励制造恐慌的黑红配色方案,就像各种新闻页面都有令人震惊的标题一样。可视化的确很重要,作为数据科学家,我们应该很好地意识到这一点,正如这篇文章所概述的。我知道使用开源技术,如 R Shiny 或 Python Dash ,可以创建一个不那么危言耸听的仪表板,与最流行的新冠肺炎仪表板不相上下。我就是这么做的!你可以在这里找到我创建的 R 闪亮仪表盘。
数据
用于所有可视化的数据由约翰·霍普金斯大学系统科学与工程中心(JHU·CSSE)提供,他们在 Github 公共页面上分享了他们的数据。约翰霍普金斯 CSSE 汇总了主要来源的数据,如世界卫生组织、国家和地区公共卫生机构。这些数据免费提供,并且每天更新。
仪表板中使用的人口数据来源于 世界银行公开数据 。这些数据只需要做一些小的修改就可以适应约翰霍普金斯大学 CSSE 新冠肺炎分校的数据。数据集中没有的“国家”人口(大部分是岛屿实体)是用来自维基百科的数据手动添加的。世界银行有一个庞大的数据库,涵盖从性别统计到投资流动的各种主题。这个存储库是高度可访问的,要么直接使用他们的 API,要么使用大多数通用编程语言中可用的各种第三方 API 之一。这为我们提供了在仪表板中集成各种有趣的数据集的机会,这些数据集目前不包括在“主流”选项中。你可以在这里找到更多关于开发者的信息。
新冠肺炎仪表板——开源版
仪表板分为几个部分,可在浏览器窗口的左上角选择。
仪表板的总览部分显示了新冠肺炎疫情最重要的关键数字和可视化效果,例如世界地图和国家列表,以及它们各自的确诊、治愈、死亡和活跃病例数。包括一个带有简单滑块的延时功能,以了解疫情的发展。

新冠肺炎仪表板-概览部分
“绘图”部分包含可视化新冠肺炎·疫情级数的几个有趣方面的绘图。这些额外信息包括一些问题,如案件的全球演变;新案件;以及两个允许在不同国家之间进行比较的图表。用户能够手动选择她或他感兴趣的国家。大多数图都有复选框,y 轴可以切换到对数刻度,特定国家的图可以按人口进行标准化。默认情况下,在特定国家图中选择确诊病例最多的五个国家。

新冠肺炎仪表板—绘图部分(用红色标记:国家选择)
仪表板上的“关于”部分描述了动机、数据来源以及关于发展和贡献的其他信息。
考虑
请注意,这个数据不能想当然。关于新冠肺炎案件的数字有很多不确定性。我避免计算死亡率和类似的数字,因为它们相对模糊,如几个来源所述[1][2]。各国的检测制度差异很大,因此很难在各国之间进行直接比较。
技术
仪表板是使用 R shiny 开发的,它让你只用 R 代码就能构建和托管交互式 web 应用。对于 IDE,我使用的是 IntelliJ 社区版,其中有一个 R 插件,可以让你像在最流行的 R IDE 中一样有效地编写 R 代码;r 工作室。我使用的其他库有:
- Shinydashboard :提供了很多预先配置好的仪表盘元素,可以相对容易的集成。
- Tidyverse :为数据争论和处理而设计的 R 包的集合,它们共享底层的设计哲学、语法和数据结构。
- 传单 :围绕最流行的用于交互式地图的开源 JavaScript 库的包装器库。
- Plotly :一个绘图库,允许你创建多种颜色和形状的交互式绘图。
- WBstats :一个包,只需要一行代码就可以访问和下载世界银行的数据。
仪表板目前托管在 shinyapps.io 上,它有一个免费使用计划,允许您访问 shinyapps.io 云上的一些有限资源。由于资源非常有限,我需要评估更换另一家服务器/云提供商是否有意义。尽管如此,shinyapps.io 是一种发布 R 应用程序的快捷方式。
为什么要开源?
那么为什么创建一个开源版本的仪表板很重要呢?
- 开源是免费的,每个人都可以使用。
- 如果你创造了一些开源的东西,并向其他人展示你的代码,错误将会很快被发现并修复。
- 使用群体智能来改进你的产品,或者获得解决某些问题的其他想法。
- 迅速从各方面获得反馈,这样你就可以提高技能,学习新事物。
Github 的创始人 Tom Preston-Werner 大约十年前写了一篇关于为什么我们应该(几乎)开源所有东西的伟大文章,他的观点今天仍然适用!
捐助
这个项目的想法是创建一个使用免费工具的开源仪表板。我希望这个仪表板有助于为全球疫情提供更多的见解。如果你对如何改进仪表板有任何想法,或者对新的情节或这方面的任何事情,请贡献。你可以在 Github 上找到所有代码。如果你有问题,需要帮助或类似的事情,请给我留言。我很乐意帮忙!
编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
更新:
上周末,我创建了一个专门针对瑞士的仪表盘。如果您想为您所在的国家制作一个特定的仪表板,请派生存储库并添加您所在国家的数据。如果您有任何问题或需要一些输入,请随时给我留言!
来源
- https://www . medical news today . com/articles/why-are-新冠肺炎-死亡率-如此难以计算-专家权衡
- https://time.com/5798168/coronavirus-mortality-rate/
数据
感谢迷离情骇、艾弗和托马斯的校对!
[## Christoph schnenberger-数据科学家-苏黎世集团| LinkedIn
在我的童年,我小心翼翼地将乐高积木分类、组织并组装成新的东西。今天…
www.linkedin.com](https://www.linkedin.com/in/cschonenberger/)
基于机器学习算法的新冠肺炎疫情预测

新冠肺炎灾难性的爆发给社会带来了威胁
传输的早期预测可以适应采取所需的响应
编者按: 《走向数据科学》是一份以研究数据科学和机器学习为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业的健康建议。然而,本文将关注如何使用机器学习来预测疫情的传播。
介绍
我们的社会正处于一个难以置信的时代,人们试图在基础设施、金融、商业、制造业和其他一些资源方面与这种威胁生命的状况进行斗争。人工智能(AI)研究人员加强了他们在开发数学范式方面的熟练程度,以便使用全国范围内的分布式数据调查这一疫情。本文旨在通过使用来自 Johns Hopkins 仪表板的实时数据,将机器学习模型与全国范围内新冠肺炎的预期可达性预测同时应用。

Erik Mclean 在 Unsplash 上拍摄的照片
传输阶段
冠状病毒传播分为四个阶段。第一阶段始于记录的前往或来自受影响国家或城市的人的病例,而在第二阶段,病例在与来自受影响国家的人有过接触的家庭、朋友和团体中按区域报告。因此,受影响的人是可以识别的。接下来,第三阶段导致严重的情况,因为感染者变得不可检测,并且在既没有任何旅行记录也没有与受感染者有联系的个体中变平。这种情况迫使全国立即封锁,以减少个人之间的社会接触,以衡量病毒的移动。最后,第四阶段在传播转变为地方病和不可控时开始。中国是第一个感受到新冠肺炎传播第四阶段的国家,而大多数发达国家现在都处于传播的这一阶段,与中国相比,承受着更多的流行病和损失。
机器学习算法在疫情调查和预测中发挥着重要作用。此外,机器学习技术有助于揭示流行模式。因此,可能会立即准备应对措施,以防止病毒的传播( Kalipe,Gautham & Behera,2018;辛格,辛格&巴蒂亚,2018 )。此外,通过使用来自 Johns Hopkins 仪表板的实时数据,利用机器学习模型来识别集体行为以及新冠肺炎在整个社会的预期传播预测。
资料组
从约翰霍普金斯大学的官方知识库中检索到的数据集。这些数据由每日案例报告和每日时间序列汇总表组成。在这项研究中,我们选择了 CSV 格式的时间序列汇总表,其中有三个表用于新冠肺炎的确诊、死亡和康复病例,有六个属性。例如,省/州、国家/地区、上次更新、已确认、死亡和已恢复的病例。CSV 数据可在 Github⁴ 仓库中获得。
预测和分析
冠状病毒的传播将社会置于社会生活丧失的边缘。此外,调查未来的传输增长并预测传输的未来事件也至关重要。在并发中,基于机器学习选择最先进的数学模型用于预测病毒传播的计算过程,例如:
- 支持向量 Regression⁵ (SVR)
- 多项式 Regression⁶ (PR)
- 深度学习回归模型
它还涉及:
- 人工神经 Network⁷ (安)
- 递归神经 Networks⁸ (RNN)使用长短期 Memory⁹ (LSTM)细胞。
使用 python 库执行机器学习和深度学习策略,以广泛预测确诊、恢复和死亡病例的总数。这种预测将允许根据传播增长做出具体决定,例如延长封锁期,执行卫生计划,以及提供日常支持和供应。
回归分析
回归分析是机器学习算法的一部分。它是领先的机器学习算法。想象一下由任意两个变量 X 和 Y 组合而成的直线方程,可以用代数方法表示为:

其中 b 声明 y 轴上的截距,a 称为直线的斜率。这里, a 和 b 也称为回归分析的参数。这些参数应该通过适当的学习方法来学习。
回归分析包含一组机器学习方法,使我们能够根据一个或多个预测变量(X)的值来预测连续的结果变量(Y)。它假装结果和预测变量之间存在持续的联系。
相关系数
相关系数被解释为两个变量之间线性关系的强度。卡尔·皮尔逊强调,相关系数是两个变量之间线性相关的权重或程度。他还生成了一个被称为相关系数的公式。两个随机变量 X 和 Y 之间的相关系数,通常由这些变量之间线性相关性的数值度量表示,定义为:

其中, i = 1,2,3,4,…N ,是输入输出变量的集合。下面给出了一些预测:
- 如果相关系数的值等于零,则表明输入变量 X 和输出变量 y 之间没有相关性。
- 如果相关系数的值等于正 1,则表明输入变量和输出变量之间有很强的关系。换句话说,如果输入变量增加,那么输出变量也会增加。
- 如果相关系数的值等于负,则表明输入变量增加,然后输出变量也减少,以此类推。
那些线性相关性很小或没有线性相关性的变量可能具有很强的非线性关系。另一方面,在拟合模型之前估计线性相关性是识别具有简单关系的变量的一种有价值的方法。在这项拟议的研究中,我们测量了全国范围内 COVID-2019 确诊病例的日期和数量之间的相关系数。
用 Python 编码


注意:完整的源代码可以在本文末尾获得
结论
我们的环境处于新冠肺炎病毒的控制之下。本文旨在通过来自 Johns Hopkins 的数据集使用机器学习模型进行疫情分析。总之,在预测新冠肺炎传输时,多项式回归(PR)方法比其他方法产生了最小的均方根误差(RMSE)。然而,如果传播模仿 PR 模型的预测趋势,那么它将导致大量的生命损失,因为它呈现了全球传播的不可思议的增长。正如中国所认为的,新冠肺炎病例的增加可以通过减少感染者中敏感个体的数量来降低。这种新常态可以通过变得不合群和支持有控制的锁定规则来获得。
**References**#1 [Predicting Malarial Outbreak using Machine Learning and Deep Learning Approach: A Review and Analysis](https://ieeexplore.ieee.org/document/8724266)#2 [Sentiment analysis using machine learning techniques to predict outbreaks and epidemics](https://www.researchgate.net/publication/332819639_Sentiment_analysis_using_machine_learning_techniques_to_predict_outbreaks_and_epidemics)#3 [Johns Hopkins University](https://coronavirus.jhu.edu/)#4 [Johns Hopkins University: COVID-19 Data Repository](https://github.com/CSSEGISandData/COVID-19)#5 [Support Vector Regression](https://www.researchgate.net/publication/340883347_Detection_of_coronavirus_Disease_COVID-19_based_on_Deep_Features_and_Support_Vector_Machine)#6 [Polynomial Regression](https://www.researchgate.net/publication/341109515_Application_of_Hierarchical_Polynomial_Regression_Models_to_Predict_Transmission_of_COVID-19_at_Global_Level)#7 [Artificial Neural Network](https://www.researchgate.net/publication/340538849_Novel_Coronavirus_Forecasting_Model_using_Nonlinear_Autoregressive_Artificial_Neural_Network)#8 [Recurrent Neural Networks](https://www.researchgate.net/publication/341474954_How_well_can_we_forecast_the_COVID-19_pandemic_with_curve_fitting_and_recurrent_neural_networks)#9 [Long Short-Term Memory](https://www.researchgate.net/publication/340255782_Application_of_Long_Short-Term_Memory_LSTM_Neural_Network_for_COVID-19_cases_Forecasting_in_Algeria)***Disclaimer*** *This is for education and information purposes only, additional research in the machine learning algorithm needed to give the exact amount of prediction data from the real-time dataset. The source code of the experiment can be access* [***here on GitHub***](https://github.com/wiekiang/covid-predict-analyst)*.*
新冠肺炎爆发:口罩推特分析

2020 年 2 月 28 日,加利福尼亚州奥林达的一家真值五金店的招牌上写着防护面具售罄。(约翰·G·马英美资源集团/美国环境保护署-埃菲社/Shutterstock)
别买口罩了!在美国报道第二例新冠肺炎死亡一天后,卫生官员继续恳求美国人停止恐慌购物模式。虽然疾病控制和预防中心(C.D.C .)不建议健康人戴口罩以避免感染,但中国当局鼓励人们在面对新冠肺炎时戴口罩。这种对比源于西方人和东方人不同的传统和习惯。在美国最近的口罩价格欺诈背后,普通人对戴口罩的态度引发了我的好奇。他们在网上聊些什么,整体情绪如何?他们的言论有没有网络效应?在下面的帖子中,我将通过进行推文分析来研究最近的口罩短缺问题。
目标
这个项目有两个主要目标:
- 了解人们对流行偶像口罩的态度
- 看看人们的推文是否有网络效应,找出热门话题
在方法论方面,我将使用数据挖掘技术、情感分析和网络分析来实现上述两个目标。
数据理解
通过一个 Twitter 开发者账户,我从网站上提取了 1200 条包含关键词“面具”的推文。如下所示,原始数据有 16 列和 1,200 行。第一列包含 tweet 的内容,其他列描述参与度、时间和用户 ID 等信息。

表 1。部分原始数据
数据清理
如图 1 所示,很难分析原始杂乱的语料库。通过使用 R 中的 NLP 包,我从语料库中删除了标点、数字、停用词、URL 和空格。此外,由于推文是使用关键字“mask”提取的,我更关心的是与其一起出现的单词,而不是它本身。因此,我创建了一个字典,包括不必要的单词,如“面具”和“面具”,并从文本中清除。

图一。部分原创推文
了解文本挖掘的复杂性也很重要。一个词可以有多种意思。面膜也可以和护肤之类的话题有关,和我的学业无关。下一步我会解决这个问题。
数据探索
数据可视化让我们有了一些初步的了解。

图表 1。频率术语
不出所料,人们的推文集中在新冠肺炎疫情上。像“需要”、“重要”、“计划”这样的词让我们看到了他们的态度。他们还谈到了当前市场的供需不平衡。值得注意的是,右边有两个奇怪的术语,“布伦内尔”和“电影”这是一个关于克里斯·布伦内尔写的一部叫 M.A.S.K .的即将上映的电影的话题。通过下面的单词云,我看到了更多不必要的单词,如“通宵”

图 2。术语的词云
现在不相关的单词会直观地出现。我回去删除了所有这些推文,继续处理剩下的 1127 条推文。
情感分析
每个字背后都有情感。R 中的“syuzhet”包有助于在文本中捕捉人们的情绪。

图表 2。面具推文的情感评分
上述情节表明,推文更多地与预期和信任有关。人们在推特上确实有一些负面情绪。条形图显示,大约 30%的人在网上表达过恐惧,大约 50%的人表现出负面情绪。但总的来说,推特上的人们对流行偶像面具持乐观态度。
网络分析
虽然情感分析有助于了解个人的态度,但网络分析可以识别社交平台上的关系。在推文分析中,每个词都是一个顶点;顶点的度数表明了它与其他词的联系。例如,我们可以从下面的例子中看出,“冠状病毒”通常与“get”一起出现。'

图 3。一起出现的术语
从下面的直方图来看,右偏度表示大多数推文的度数值较小。右边的尾巴上也有一些极端值,意味着一些术语与其他术语有密切的联系。

图表 3。节点度直方图
那些流行的术语是什么?下面的网络图提供了一个更清晰的外观。为了避免混乱的显示,我只包含了频率超过 30 的术语。

图 4。术语可视化
关联术语是那些在 Twitter 上一起出现的术语。“冠状病毒”这个词位于网络图的中心,与所有其他术语相关。然后我根据边的介数将所有的单词聚集在一起。

图 5。基于边介数的聚类
介数表示一个节点位于其他节点的测地线路径之间的频率。这三组主要是关于正在发生的流行病、口罩的重要性和口罩的使用。
在看到术语之间的关系后,我继续讨论网络对推文的影响。

图 6。带有 tweets 的顶点
上面的图显示了推文的分布。我们可以看到很多推文没有连接(稀疏区域的离散点)。由于高参与度的推文更令人感兴趣,我删除了那些连接度较低的推文,得到了一个更详细的网络图,如下所示。

图 7。一个详细的推特网络
上面的数字代表原始数据中 tweets 的 ID。这两个密集区域的推文最常被点赞、转发和评论。然后,我从圈出的区域中随机挑选了一些推文,看看人们在 Twitter 上谈论的是什么。

图 8。Twitter 上参与度较高的精选推文
由于这些推文在网上引发了最多的讨论,我们现在知道了人们最关心的问题:
- 他们不确定谁需要戴口罩来降低感染风险。
- 他们对最初的旅行计划犹豫不决。
- 他们关注新冠肺炎预防政策的变化。
- 他们提醒出现症状的人采取行动。
- 口罩的抢购模式还在继续。
部署
关键问题是“那又怎样”尽管文本挖掘是计算机科学的一个相对较新的领域,但它已经逐渐被应用于风险管理和客户服务等领域。新冠肺炎疫情刚刚在美国爆发。此时,文本挖掘技术有两个主要部署。
- 零售商和供应商可以了解人们随着时间的推移而改变的态度,从而相应地调整库存和生产计划。
- 当局可以知道人们的担忧和不确定性,给出明确的方向,并制定有益于人民的新政策。
最后,我的学习有两个改进点。首先,“syuzhet”软件包的一个主要问题是它没有适当考虑负面因素,这可能会对敏感性分析产生一些影响。其次,提取的推文数量可以更多,以捕捉在线全貌。
基于使用 AutomaticAI 的常规血液检查的新冠肺炎患者筛选和风险评估
创造一种可能的人工智能解决方案来帮助医生对抗新冠肺炎

图片由Fernando zhimaicela通过 Pixabay 拍摄
问题的背景
大自然再次证明了它的力量,证明了即使在我们的文明世界里,我们也不是大自然的主人,但我们是大自然的一部分。
冠状病毒疾病于 2019 年 12 月被发现,我们仍在努力,我们不知道如何确切地对抗它,尽管有所有的计算能力,所有的技术发明和全世界所有梦想殖民火星或在月球上争夺土地的聪明人,我们仍然没有任何针对这种显然新病毒的解毒剂。
我认为,我们应该脚踏实地,寻找更有用的解决方案,帮助我们拯救我们的世界,而不是做殖民火星或从月球上开采矿物的梦。寻找新的可居住的行星并离开地球不是一个解决方案,但这只是一种懦夫的生存行为。我们有很多更实际的问题需要解决,比如饥饿、污染、全球变暖,现在还有新冠肺炎。我们应该集中精力帮助我们的人民,帮助那些活在当下、现在需要帮助的人。从局部开始,如果你甚至不能帮助你自己或你的家人,不要急于改变整个世界。
在这些艰难的日子里,有许多当地英雄,他们尽最大努力抗击新冠肺炎,帮助医生的日常工作,尽可能挽救更多的生命,他们提供免费服务,如为老人购物,运送货物,甚至缝制自制的口罩。我们应该感谢他们在这些危险的日子里所做的努力。
我想强调一个来自 Cluj-Napoca 的开发者团队展示的利他主义的特殊故事。这是一家初创公司的故事,一家名为 Spectro 的小公司。Life ,一家致力于通过使用结合人工智能的物联网解决方案来帮助糖尿病患者的公司。
即使这是一个收入很少的初创公司,他们也很快将他们的糖尿病监测解决方案变成了一个新冠肺炎监测应用程序,帮助医生全天候远程监测感染者。该应用程序完全免费,此外他们向买不起这些小玩意的人提供免费的传感器和智能手表。实际上,他们掏空了自己的口袋来帮助我们,帮助抗击疫情。他们是真正的生活英雄,我们应该以他们为榜样,每个人都可以成为英雄,每个人都可以帮助,英雄主义是一种选择而不是一种特权。你可以在 国际新闻发布 和他们的 主页 上找到更多关于这个项目的信息。
为了有助于对抗冠状病毒,在这篇文章中,我想介绍一种利用人工智能对抗新冠肺炎的可能方法。这只是一个想法,一个起点,而不是最终的解决方案,但它可以进一步发展,以创建一个更可靠的解决方案。
使用人工智能进行新冠肺炎风险评估和患者筛选
为了控制冠状病毒的传播,识别已经被这种新型病毒感染的人是非常重要的。为了检测这种病毒,金标准是 rRT-PCR (逆转录聚合酶链反应)检测。但是有一个问题,这种测试是费时费力的手工过程,而且供应量非常少。所以问题是,我们能不能想出一种替代的方法来过滤掉健康的人,并评估感染的风险,这种方法减少了所需的新冠肺炎检测的次数。此外,我们希望创建一个自动过滤算法,,这样医生就不会浪费时间来评估和选择需要进一步测试和评估的患者。
在接下来的章节中,我们将介绍一种基于常规血液检测结果的初步患者过滤算法。为了选择最佳匹配的人工智能模型并调整其超参数,我们使用了 自动 。
自动 是一种通用算法,可用于任何类型的分类或预测问题,它会根据输入数据自动调整自身并选择最佳匹配算法。通过将该算法与一些预处理以及可能的一些特征提取步骤相结合,我们可以以相当高的分数(准确度、精确度、召回率等)解决几乎任何种类的分类(或回归)问题。).
其类似于 Auto-Sklearn 或 Auto-Weka ,主要区别在于 AutomaticAI 使用 群体智能 结合模拟退火 来寻找最佳匹配模型并尽快调整其超参数。
使用pip install automatica命令,可以从 安装 PyPi 库。算法的源代码可以在这里 找到 。
提议的解决方案管道

数据集
这个 [数据集](http://This dataset contains anonymized data from patients seen atthe Hospital Israelita Albert Einstein, at S ̃ao Paulo, Brazil. Alldata were anonymized following the best international prac-tices and recommendations. All clinical data were standardizedto have a mean of zero and a unit standard deviation. Dateshave been omitted and the information on the patient’s sex hasbeen coded.) 包含来自巴西圣保罗的以色列阿尔伯特爱因斯坦医院(Israelita Albert Einstein Hospital)的匿名数据。所有数据均按照国际最佳做法和建议匿名化。所有临床数据均标准化为平均值零和单位标准偏差。日期被省略,关于患者性别的信息被编码。
它包含大约 5000 多名患者的数据,每个患者有 100 多个特征。特征之间包含常规血液检测结果,具有白细胞、Mematocrit、血红蛋白、血小板、平均血小板体积等属性。除常规血液检测值外,还包含呼吸道合胞病毒、流感嗜血杆菌、乙型流感病毒、鼻病毒/肠道病毒等病毒(不同于冠状病毒)的不同检测结果。
预处理
此数据集的唯一问题是,它包含大量缺失数据。因此,第一个预处理步骤是删除血液测试完全缺失的所有行。有多个列与我们的问题不相关,因此我们也将删除不相关的列。此外,将仅保留缺失数据不超过 70%的列。
得到的数据集非常不平衡,有 500 多个负面示例,只有少数正面示例,如下图所示:

为了处理这个问题,我们使用了 XAI 的 库从 伦理 ML 为过采样。以 0.4 的速率运行过采样算法后,我们得到以下结果:

我们不想以更高的速率运行过采样,因为这将导致过拟合。
下一步是分离独立变量和因变量,因此要从要素中分离标签。由于 AutomaticAI 不能将字符串作为标签,我们将“正值”转换为 1,将“负值”转换为 0。
在运行自动算法之前,我们希望确保在训练数据中不再有缺失数据,因此我们再次运行数据,并用该特定特征的平均值填充所有缺失数据。
下一步是将数据分成训练集和测试集。
下一步是运行自动算法,为我们的数据找到最佳模型,并自动调整其超参数。
运行这个算法后,选择的模型是 RandomForestClassifier ,其f1-得分为 95% ,这确实是一个令人印象深刻的结果。

为了评估我们的模型,我们绘制了混淆矩阵。
由此产生的混淆矩阵可以在下图中看到。我们可以清楚地看到,结果非常好,与 213 个正确的结果相比,该模型只犯了 6 个错误。

除了分类结果(0 表示阴性,1 表示阳性)之外,该模型还返回一个介于 0 和 1 之间的值,该值表示分类结果的置信度。该置信值可用于风险评估。如果分类结果为阳性且置信度高,这意味着患者被冠状病毒感染的可能性高,因此需要进一步调查。如果结果是阴性,那么病人是健康的,所以我们没有必要在健康的病人身上浪费新冠肺炎测试。这可以减少所需的新冠肺炎测试和的数量,帮助医生自动筛选出处于危险中并需要医疗护理的患者。
解释结果
医疗领域需要高度的问责制,因此也需要透明度,这意味着我们需要能够解释机器决策、预测并证明它们的可靠性。
为了解释最佳模型的结果,即 RandomForestClassifier ,我们使用了特征重要性。可以使用 XAI 库计算特征重要性,如下所示:
这将生成如下图所示的图表:

正如我们所料最重要的特征是白细胞或T3 或白细胞计数。白细胞数量高于或低于正常值可能表明潜在疾病。白细胞计数可以检测你体内隐藏的感染,并提醒医生未诊断的医疗状况。白细胞主要有五种类型:中性粒细胞,淋巴细胞,嗜酸性粒细胞,单核细胞和嗜碱性粒细胞。因为高嗜碱性粒细胞与病毒、细菌或其他类型的感染无关,但它是甲状腺功能减退的常见迹象,所以在特征重要性图中,它显得非常低。高数量的中性粒细胞、淋巴细胞、单核细胞或嗜酸性粒细胞是病毒感染的常见迹象,因此,正如我们所料,它们在图表中具有更高的重要性值。
第二个最重要的特征是血小板。血小板是在我们血液中循环的细胞,当它们识别受损的血管时会结合在一起。血小板过多是由感染或其他情况引起的。通常血小板计数结合平均血小板体积(MPV) 进行评估,这也是一个重要特征,如图所示。当血小板通常被抗体、感染或毒素破坏时,会出现低血小板计数和高 MPV。
即使患者出现气短、疲劳、高血压、意识模糊或呕吐等症状,如果肌酸水平较高,则是肾衰竭或糖尿病的迹象,因此不是冠状病毒引起的。这就是肌酸在特征重要性图中也有很高分数的原因(用于排除冠状病毒)。
其他特征如直接胆红素、间接胆红素、钾等。也被模型用于排除新冠肺炎感染,因此这些特征将降低冠状病毒感染的风险。
结论
在本文中,我们介绍了一种使用人工智能对新冠肺炎患者进行初步筛选和风险评估的可能解决方案。
最佳人工智能模型是由库自动选择的,通过使用一些预处理步骤,如处理缺失和不平衡数据,选择的模型获得了令人印象深刻的结果。****
为了增加该算法的可信度,我们使用了【XAI】库来使用特征重要性图解释结果。
**数据集和完整代码**可以在下面的 git 资源库中找到: 新冠肺炎-患者-过滤-使用-自动化 。
感谢您阅读本文!如果你喜欢它,请在媒体上跟随我!谢谢大家!
编者注: 走向数据科学 是一份以研究数据科学和机器学习为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
****成为媒介上的作家:https://czakozoltan08.medium.com/membership
我真的很喜欢咖啡,因为它给我精力去写更多的文章。如果你喜欢这篇文章,那么你可以给我买杯咖啡来表达你的欣赏和支持!
新冠肺炎:人员层追溯
对捷克共和国个人层面数据的深入分析

来源:( enriquelopezgarre )通过 pixabay (CC0)
介绍
主要有较大人群的累积新冠肺炎统计数据,例如国家一级的感染人数。
由于有价值,它很少告诉我们关于我们父母所属的年龄/性别群体,或我们伴侣的群体,或我们兄弟姐妹的年龄/性别的新冠肺炎情况。

鸣谢:丹·佩尔乔夫斯基, 捷克国家技术图书馆内景照片
让我们全面深入了解关于年龄和性别组的个人信息。
数据
我们将调查有关捷克新冠肺炎患者的数据,这些数据可在捷克卫生部 网页 获得。为了将新冠肺炎的情况放入人口统计背景中,我们将使用来自捷克统计局 网站 的数据。
请注意,关于阳性新冠肺炎病例的数据很可能偏向于不仅感染了新冠肺炎病毒,同时还出现了中度、重度或严重症状的人。我们还是说“感染新冠肺炎/接触新冠肺炎”而不是更精确但冗长的“感染新冠肺炎并有中等、严重或危急症状”。
第一部分.深入了解我们如何导入新冠肺炎
我们知道新冠肺炎不是起源于捷克共和国。让我们调查一下我们所知道的有关新冠肺炎输入病例的情况,从总体概述开始,然后深入到更详细的细节。
概述
每个暴露国家的输入性新冠肺炎病例总数是多少?

我们已经看到了进口病例来自的地方。现在让我们概述一下发生在什么时候。

好消息是,最近输入性新冠肺炎病例的绝对数量似乎有下降趋势。
暴露在哪个国家,有多少病人?
每个暴露国家的捷克患者人数,及时
让我们首先检查不同国家的累计计数。
为此,我创建了一个交互式可视化,可以通过 这个链接 访问。请随意探索各种细节,亲自体验可视化。
作为开胃菜,对于每个单独托管的交互式可视化,我将发布简短的 gif 和简短的评论。

在上面的 GIF 上,我们可以看到新冠肺炎是如何从意大利进口到捷克的。后来,全世界的捷克人都接触到了新冠肺炎。然而,意大利和位于意大利和捷克之间的奥地利仍然是主要的投资国。有趣的是,没有一个捷克病人在中国接触到这种病毒。
我们已经看到了每个国家的累计总数的演变。现在让我们检查每个暴露国家每周输入的新冠肺炎病例数。对于 GIF,我将重点关注欧洲。

再次,请随意通过 这个链接 来玩这个互动可视化。
放大到欧洲,我们可以看到,在疫情爆发的前几周,几乎所有输入性新冠肺炎病例都来自意大利。后来,虽然意大利仍然是主要的暴露源,但奥地利成为第二大病毒暴露源。后来,每周进口的大部分原产于奥地利。最后,进口数量下降了。这给人的印象几乎是,我们看到了一波从意大利到捷克的进口潮,奥地利是意大利和捷克之间的主要转运点。
在调查输入捷克共和国的新冠肺炎病例时,我们同时检查了“来自哪里、何时、有多少?”。然而,我们还没有分析病人的性别。现在让我们来关注一下。
什么性别的病人,什么时候?
及时输入新冠肺炎的患者中女性的比例
让我们来看看每周输入新冠肺炎的捷克男女患者的数量。


首先,通过每周汇总,我们可以更好地看到男性和女性输入病例总数的减少。让我们希望它保持这样。
第二,我们可以看到,在输入的新冠肺炎病例中,男性系统性地多于女性。它适用于所有年龄组吗?让我们深入到年龄/性别组。
不同性别患者的年龄?
让我们先来看看每个年龄段每个性别的输入病例总数。


有趣的是,20 多岁的男性和女性有相似的进口活动,女性实际上更活跃。然后,对于男性和女性来说,“进口活动”随着年龄的增长而下降,直到 40 岁,这种下降对女性来说尤其迅速。根据官方统计,捷克首次生育母亲的平均年龄为 29 岁(来源于捷克文)。继续到更高的年龄组,我们可以看到男女两性对应于 45 岁左右的局部分布模式。与 30 多岁的女性相比,40 多岁的女性输入了更多的新冠肺炎病例。然而,总体而言,40 多岁的男性是最活跃的输入群体。
暴露国家中最活跃的年龄/性别群体是否相同?让我们找出答案。
根据不同的接触国家,哪个年龄/性别组最活跃?
让我们创建单独的交互式可视化,一个针对女性,一个针对男性。两种可视化将共享相同的色标,以便我们可以在视觉上比较选定的年龄/性别组。人们可以通过将鼠标移动到可视化的相应框来检查来自任何国家/年龄/性别的病例的精确计数。
我们可以看到,典型的患者年龄因国家而异。
例如,在联合王国,20 多岁的年轻人是男女输入病例中最大的年龄组。
在暴露于新冠肺炎病毒的捷克患者中,40 多岁、50 多岁和 60 多岁的人群数量最多,同性别的 60 多岁男性多于女性。
另一方面,与意大利病例相比,从奥地利输入的病例对应于更年轻的年龄组。
这些差异可能暗示了访问一个国家或另一个国家的主要原因(例如,学习相对于工作相对于家庭娱乐)。
在奥地利,我们可以看到男女年龄分布的差异。20 多岁的女性是在那里感染新冠肺炎病毒的女性中人数最多的年龄组。此外,就奥地利而言,这一年龄组的妇女多于男子。关于在奥地利接触到病毒的男性,30 多岁和 40 多岁的男性是捷克新冠肺炎进口商中最活跃的群体。在所有国家的所有年龄/性别群体中最活跃。
在上面的分析中,我们没有调查导入的时间。特定年龄/性别群体的进口活动是否会随着时间而变化?
哪个年龄/性别群体在特定日期最活跃?
很高兴看到最近所有年龄/性别群体的进口活动都在减少。
在其他观察结果中,人们可以注意到 60 多岁男性的输入病例在 3 月份有所增加,而对于 20 多岁或更年轻的男性,总的趋势正好相反。
我们首先看到了每个不同国家输入的新冠肺炎病例的年龄/性别统计,然后我们及时检查了每个年龄/性别的输入。现在让我们尝试结合这两种观点,及时检查每个国家输入病例的性别比例。
暴露在什么国家,什么性别,什么时候?
按暴露国家分列的输入新冠肺炎病毒的患者中女性的比例
让我们用我在这里主持的互动可视化来调查女性在新患者中的每周比例。

我们正在分析每周汇总。然而,有时我们只有一两个从某个国家传入的病例。然后,颜色告诉我们一个人的情况。更有意思的是检查每周病例数较多的主要“进口国”的可能趋势:意大利和奥地利。
义大利

似乎意大利出口的男性和女性的比例一直大致相同(可能除了三月的第二周和四月的第一周,那时男性略多)。我很好奇,在意大利接触到病毒的病人来自捷克的哪个地区。

奥地利

除了 3 月中旬和最后一周总共只有 8 个病例外,澳大利亚感染新冠肺炎的男性患者明显更多。那些可能主要是商务旅行吗?让我们也快速检查一下奥地利病例输入到了捷克的哪些地区。

最后,我们还将及时检查每个国家的平均进口年限。
暴露在哪个国家,多长时间,什么时候?
可以在 处找到 能够详细调查年龄信息的交互式可视化。
作为一个人们可能会好奇的例子,我想看看年轻人什么时候从英国带来了新冠肺炎。

有趣的是,在 3 月下半月和 4 月初,英国进口商的平均年龄下降了。简单地搜索了一下,在这个网页上,我看到了给学生留在家里的“基本建议”,日期是 3 月 24 日。这可能是对我们所看到的现象的一种可能的解释吗?
输入性新冠肺炎病例应该是我们的主要关注点吗?
要回答这个问题,让我们来看看每天输入性病例与本地病例的比例。

分析捷克共和国的总体情况很重要。
第二部分。捷克地区追溯
从捷克所有新冠肺炎患者的概况开始,深入分析谁、何时、何地
概述
让我们首先检查高层次的总结。新冠肺炎阳性患者每个性别的总体年龄分布是什么?

我们可以观察到女性和男性的分布有两个有趣的差异。
与同年龄组的男性相比,30 多岁的女性似乎较少感染新冠肺炎病毒。70 多岁的女性和男性的情况也是如此。此外,30 多岁的女性比 20 多岁的女性更少出现电晕。我们已经提到过,在捷克,第一次做母亲的平均年龄是 29 岁,所有生育的母亲的平均年龄是 31 岁。生孩子会导致更有效的自我隔离和社会距离,导致观察到的 30 多岁女性比例吗?我们稍后将检查年龄/性别组在总人口中的比例,然后得出结论。
我们已经检查了病人的性别。新冠肺炎患者在各地区的总体分布情况如何?

哦,布拉格…应该注意的是,根据官方统计,中央波希米亚地区的总人口略高于布拉格的人口。然而,布拉格的人口密度高出 30 多倍,这可能意味着社交距离明显更难。
我们已经分别看到了“谁”(年龄分布)和“哪里”(地区分布)。现在,让我们深入了解组合细节。
谁在哪里?
让我们使用交互式可视化来查看每个地区每个性别的新冠肺炎患者的年龄分布。
我们之前已经看到,与 20 多岁的女性相比,30 多岁的女性新冠肺炎病例较少。现在我们可以看到,在几个地区,同样的情况也适用于男性!
人们还可以注意到不同地区年龄分布的不同变化。例如,Olomouc 的女性分布向年轻女性转移,而úSTínad Labem 似乎向老年妇女略有转移。然而,根据官方人口统计,Olomouc 地区女性的平均年龄略高于úSTínad Labem 地区女性的平均年龄。众所周知,奥洛穆茨是一个“学生”城市,那里 1/5 的人口是来自全国各地的学生(捷克语中的引用)。这一观察将有助于我们对高危人群进行分析。
所以,我们一直在看“谁”和“哪里”,完全忽略了疫情的时间线。再加上“什么时候”的问题吧。进入我们的下钻!
何时何地?每个地区的新冠肺炎患者人数

交互可视化可以在 这里 找到。
最终的累积计数支配了早期的统计数据,使得很难直观地检查开始时发生了什么。对数色标将使我们能够更好地看到流行病的早期阶段,关于对数色标的更多细节可以查看相应的维基页面。

我们可以看到疫情是如何在乌斯季和布拉格开始的,然后中部和东部地区成为新冠肺炎的领导者,直到我写这篇博客的时候,他们一直是“领导者”。
我们及时调查了每个地区的阳性病例总数。现在让我们及时检查每个年龄/性别组的新冠肺炎患者。
谁和什么时候?每天每个年龄/性别组的新新冠肺炎患者计数
详细的可视化使我们能够检查,例如,老年人群体。我们可以看到,在流行病开始时,60 多岁的男性是当时所有男性年龄组中每日新新冠肺炎病例数最高的人群之一。我们知道,捷克政府很早就实施了保护老年人的额外措施。从数据中我们可以看到,对于 60 岁以上的人来说,新患者的日增长率并没有像年轻群体那样增长。在大约一周的时间里,60 多岁的人每天的新增病例数下降。然而,后来这个数字开始上升,特别是这个年龄段的男性,这个数字在同一日期接近其他年龄段。另一个令人不安的观察结果是 40 多岁的女性新增病例数很高。
现在让我们调查每个地区新患者的性别比例。
什么性别,什么时间,什么地点?
每个地区每周新增女性患者的比例
为了减少噪音,我们计算并可视化每周统计数据。

请随意自己玩交互式可视化,检查各种细节。可视化坐在这里。
可视化使我们能够看到,新女性和新男性患者的数量通常是不同的,即使是在随后几周的更大样本中,当有许多新的新冠肺炎患者时。让我们注意到这一周是从 3 月 30 日开始的。在所有地区,新的新冠肺炎阳性患者中女性更多。
那一周新病人的平均年龄是多少?让我们检查一下。
多大,什么时候,在哪里?
每个地区新患者的平均年龄
同样,您可以在这个地址上找到交互式可视化,并检查任何细节。
在这里,我将重点关注从 3 月 30 日开始的这一周,我们注意到这一周女性新患者的比例有系统地上升。

似乎在这一周,40 多岁的人感染新冠肺炎病毒最多。这可能表明,在捷克,40 多岁的女性可能是感染新冠肺炎病毒风险较高的年龄/性别群体。
让我们更正式地分析每个年龄/性别群体感染新冠肺炎的风险。
第三部分。每个年龄/性别群体感染新冠肺炎病毒的风险
首先,让我们检查一下,与我们基于人口统计学的预期相比,数据显示每个年龄/性别组的不同风险。
新冠肺炎对所有年龄性别群体的攻击是均等的吗?
让我们制定一个无效假设,新冠肺炎随机攻击任何人,不管什么年龄/性别组。接下来,让我们检查数据是否提供了足够的证据来反对这个假设。如果是这样,我们就拒绝这个假设。这就是统计学家经常使用数据来验证事实的方式。这是一个相关的笑话。

来源:XKCD(CC0)****
关于我们将如何检查这一点的详细信息
在这一部分,我将提供一个简短的统计介绍。有很强统计学背景的读者可能想跳过这一节。另一方面,如果能对我的描述进行修正,我会很感激。
我们将使用捷克人口统计数据来计算每个年龄/性别组的比例。利用这些比例,我们将计算每个年龄/性别类别中新冠肺炎阳性患者的预期频率。如果零假设成立,也就是说,如果每个年龄/性别组的新冠肺炎收缩率相等,我们就可以预期这些频率。
然后,我们将使用一个数字来总结这些预期频率和观察到的频率之间的差异,称为统计卡方,表示为 χ 2。数学家们知道如果零假设为真,χ2 的不同值有多大的可能性。这将使我们能够检查如果不同的年龄/性别群体平均收缩新冠肺炎,我们的数据是多么不可能。在此基础上,我们将决定我们是否应该拒绝零假设。
事先达成一致是一个好习惯,在这种情况下,我们将拒绝零假设,否则,人们可能会试图将自己的信念投射到对结果的解释中。罗纳德·科斯曾经说过,
如果你折磨数据足够长的时间,它会承认任何事情。
我们很快会看到另一个关于测试结果解释的笑话,但是为了让每个人都完全理解它,我们需要刷新一个 p 值 的定义。
我们已经讨论过统计数据 χ 2 总结了我们观察到的和我们期望的之间的差异。 χ 2 值越高,差异越大。换句话说, χ 2 值越高,我们的数据越不可能是真的。 P 值是当零假设为真时,得到我们的 χ 2 值或 χ 2 值甚至更高的概率(即证明假设更不成立的值)。
综上所述,我们得到的 p 值越低,我们在真零假设假设下的观测值就越不可能,因此拒绝零假设就越安全,这表示为 H₀ 。
如前所述,在进行统计实验之前,最好就 p 值“低”的含义达成一致。通常,我们会设置一个阈值来与获得的 p 值进行比较。如果 p 值小于阈值,则无效假设将被拒绝。这个阈值称为显著性水平,用α 表示。我们同意测试新冠肺炎是否以α = 5%的显著性水平平均攻击所有年龄/性别组。
关于结果解释的笑话来了。

来源:XKCD(CC0)****
如果对我们将要执行的统计测试的技术细节感兴趣,人们可能会想看一个来自可汗学院的短片。
卡方检验结果
我们已经检查了皮尔逊卡方检验的前提条件,然后得到 p 值= 1.8*10⁻ ⁶。因此,我们安全地拒绝显著性水平为α = 5%的零假设。
让我们直观地比较观察到的新冠肺炎年龄/性别比例与人口比例。
****
鉴于 20 岁以下人群的比例差异如此之大,我们拒绝零假设也就不足为奇了。
现在让我们分别检查每个年龄/性别类别。因为我们将使用相同的数据样本执行多个测试,所以让我们应用 Holm 校正。
同一数据多次测试有什么问题?
同样,有很强统计背景的读者可能想跳过这一部分。
使用相同的数据进行多重测试会导致所谓的多重比较或多重分析问题。问题类似于多次掷骰子。

来源:( ID 955169 )通过 pixabay (CC0)
我们知道得到 6 的概率是 1/6 或大约 17%。让我们想象一下,你掷骰子得到了 5 英镑。你对你的“分析”结果不满意,所以你重新掷骰子。假设你又不开心了,所以你再掷一次,这次你得到了想要的 6。然而,当掷出三个骰子时,至少有一次得到 6 的概率是 42%,而不再是 17%。
如果您测试数据样本的多个子组,也会发生类似的情况。子群越多,子群中的一个就越有可能偶然“坦白”,正如科斯的名言
如果你折磨数据足够长的时间,它会承认任何事情。
因此,当对多个组重复相同的假设检验时,偶然得到某个组的低 p 值的风险更高。在这种情况下,我们会错误地拒绝一个真正的零假设。这种类型的误差称为 I 型误差。

可以看出,对于显著性水平为α的单一假设检验,I 型错误的概率小于或等于α。
如果我们希望在多次测试的情况下将 I 型错误的概率保持在α之下,我们需要在与α比较之前校正 p 值。最基本的校正是所谓的 Bonferroni 校正,对于 m 测试,在与α比较之前,每个 p 值乘以 m 。然而,Bonferroni 校正非常保守,并且已知经常不能拒绝错误的零假设。在我们的案例中,这意味着不同年龄/性别的人群感染新冠肺炎病毒的风险是不同的,但我们无法拒绝风险相同的无效假设。

这种类型的错误被称为第二类错误。
我们将使用 Holm 校正,它是 Bonferroni 校正的改进,技术细节可以在 wiki 中找到,例如。应该注意的是,该测试仍然相当保守,仍然可能导致第二类错误。
关于分组卡方检验的一个注记
有经验的读者已经注意到,通过逐组执行卡方检验,我们将得到一个具有一个自由度的卡方分布,这只是一个平方正态分布。因此,实际上我们将做一些类似于 z-test 的事情来检验比例的差异,因此我们必须检查相应的前提条件,我们已经这样做了。90 岁以上的预期男性患者不到 10 例,因此我们将 90-110 岁年龄组排除在分析之外。
每个年龄/性别组的单独结果
根据霍尔姆校正的重复测试结果,对于大多数年龄/性别组来说,零假设被拒绝,取而代之的是年龄/性别组不会随机暴露于新冠肺炎。
让我们计算新冠肺炎年龄/性别群体比例与基于人口统计的预期比例之间的差异。对于随机暴露于新冠肺炎没有统计差异的组,让我们插入零。让我们用红色描绘增加的新冠肺炎曝光,用绿色描绘减少的曝光。
雌性

雄性

我们只是利用了新冠肺炎和总人口比例之间的直接差异。让我们使用置信区间来计算比例中数量差异的更保守的估计。
年龄/性别组比例的置信区间和更保守的风险定量评估
让我用一个具体的例子来说明我将要做的事情。我母亲属于 50-59 岁之间的女性,我将用这个群体作为例子。
- 首先,我将根据新冠肺炎的数据估计 50-59 岁女性的人口比例。群体比例的 99%置信区间为 7.1-9.6%。如果这个特定的年龄/性别群体被随机暴露在病毒中,这是一个很可能属于的人口比例的间隔。
- 然后,我们使用人口统计数据计算 50-59 岁女性在人口中的实际比例。实际比例为 6.2%。
- 将置信区间与真实比例进行比较,我们得出结论,新冠肺炎比例比人口比例至少高 0.9%
结果总结如前:
雌性

雄性

对于风险增加的年龄/性别组,让我们将风险增加与组比例一起可视化。
****
结束语
一些见解:
- 对于捷克女性和男性来说,20-29 岁、40-49 岁和 50-59 岁年龄组接触新冠肺炎的风险明显高于随机人群。
- 可能的原因是什么? - >这些是活跃的群体,即使在正式的紧急状态下也必须上班
- 30-39 岁的女性和男性没有更高的风险。为什么? - >一开始是一个令人费解的观察。然后,我查了一下,捷克母亲出生时的平均年龄是 30.1 岁(来源于捷克)。这意味着在 30-39 岁的人群中,有许多孩子的父母。幼儿园和学校都关门了,家长们经常必须呆在家里照顾孩子。
- ****给每个人的一个信息:这个年龄组的大多数父母不得不呆在家里带孩子,因此更系统地远离社会,这表明了社会距离对于新冠肺炎预防是多么重要。每个人都可以发挥作用!
- 谢天谢地,保护老年群体的有效国家政策似乎起了作用。然而,这些政策似乎对女性更有效。因此,对于 60 岁和 70 岁的男性来说,暴露于新冠肺炎的几率并不比随机的少很多,而对于同年龄的女性来说,暴露的几率要少很多。也许值得进一步调查这一事实,看看这是否是由于女性更好的管教/更多地呆在家里陪孙子/其他原因。
- 令人欣慰的是,输入病例的比例正在下降,证明政府的旅行限制是正确的。
- 似乎我们可以对最年轻的近亲保持合理的冷静。我仍然认为,即使是 19 岁以下的人也不应该放松警惕,因为众所周知,没有症状的人仍然可以传染给他人。
局限性讨论
- 如前所述,关于新冠肺炎阳性病例的数据很可能偏向于那些不仅感染了新冠肺炎病毒,同时还出现了中度、重度或严重症状的人。根据数据部分的协议,整个帖子由“签约新冠肺炎/接触新冠肺炎/ect。”我们指的是“感染新冠肺炎并有中度、重度或危急症状”。
- 其次,数据中的新冠肺炎样本很可能偏向于那些自己想接受测试的人。例如,可能有一些症状温和的新冠肺炎阳性患者在疫情期间不愿意去卫生机构就诊,并且没有记录在案,而一些症状温和的新冠肺炎阳性患者可能更愿意去检测中心就诊。
- 此外,在流行病爆发之初,检测能力可能不足,这可能会带来额外的偏见,例如,在最初几周,可能会对有严重症状的病例产生偏见。
- 接下来,我们只分析了新冠肺炎阳性确诊病例的数据。我们没有关于人的死亡率或病毒后果的信息,这对于分析是非常重要的。
- 此外,我们没有关于患者原有健康状况的信息,而这些信息对于分析也是至关重要的。
总的来说,我认为这种探索性的数据分析是相对初步的,我建议一旦有了更好的个人水平的数据,就重复并扩展它。
如果感兴趣的话,请随意分析这些数据,或者通过派生相应的或者 GitHub repo 。
大家保重,保持健康!
编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
新冠肺炎帖子:包含 400 多个新冠肺炎博客帖子的公共数据集
在过去的几个月里,我们从 R 社区收集了数百篇新冠肺炎的博文。今天,我们很高兴公开分享这个数据集,以帮助那些希望通过释放 R 及其社区资源来分析新冠肺炎数据的博主们能够研究这样的帖子。
到目前为止,我们已经发现并记录了 423 篇英文的 COVID 帖子。为了鼓励其他人探索这样的帖子,我们发布了一个闪亮的网络应用,它允许用户找到写这些帖子的 231 位博主的名字,他们的角色,以及他们关注的国家。该应用程序还允许用户通过主要话题、帖子标题、日期以及帖子是否使用了特定的数学技术或数据来源来交互式搜索帖子集合。为了更多地了解这个数据集的演变,其中一位作者(里斯)在 Medium 上发表了九篇文章,你可以在这里找到。
我们鼓励用户提交他们自己的帖子或者其他人的帖子来收录,这可以在这个谷歌表单上完成。我们的数据集,以及闪亮应用的代码,可以在 GitHub 上获得。如果任何人对数据集有任何更正,请写信给里斯莫里森(点)com。
这篇文章的剩余部分强调了新冠肺炎文章数据集中的一些发现。正如接下来的情节所显示的,这绝不是对新冠肺炎的每一篇博文的全面回顾,而是对我们已经发现的数据的概述。
一段时间内的帖子
随着疫情的进展,越来越少的博客作者关注 COVID 相关数据,因为我们注意到博客帖子在 2020 年 3 月达到峰值。

一些博客作者多产;更多的人已经合二为一。下面的图显示了 23 位博主的名字和帖子,他们到目前为止已经发表了至少四篇帖子。作为如何解读这一情节的例子,位于 y 轴底部的蒂姆·丘奇斯(Tim Churches)总共发表了 9 篇帖子,但没有一篇是在 4 月初之后发表的。
点的颜色对应于博客作者的工作角色,如底部图例中所述。显而易见,教授和学术研究人员在这个博客群体中占主导地位。如果你把研究生也算在内,那么几乎所有多产的博客作者都来自大学。

作者的角色
我们数据集中的博主们用各种方式描述他们的工作角色。其中一位作者(Rees)通过对大量的术语和描述进行分类,使这些工作角色标准化,但是这种努力很可能歪曲了这些博客作者的谋生之道。我们欢迎指正。
我们进一步将角色分为五大类:大学、T2、企业、T4、职业、政府和非营利组织。这些更广泛的类别在下面的图表中表示为列。

数据源
与新冠肺炎相关的大量数据来源将产生更丰富的见解。组合不同的数据集可以对一个问题有新的认识,产生改进,并允许作者构建更好的指数和测量方法。出于这个原因,其中一位作者(Rees)从我们收集的博客文章中提取了数据集信息。
在很大程度上,博客们确定了他们分析所使用的数据来源。有时,我们必须努力标准化 140 个数据源。
到目前为止,最流行的数据来源是约翰·霍普金斯大学,该大学早期、全面和一贯地为新冠肺炎数据收集和向公众传播设定了标准。

博客帖子主题
也可能是这样的情况,读者想要一个博客的摘要,或者只看属于某个主题的帖子。当然,给每篇博文指定一个主要话题会带来相当大的主观性,但我们希望这些宽泛的话题能帮助研究人员找到内容和有相似兴趣的同事。
在这里,一个气球图显示了 423 篇帖子的主要主题。主题在 y 轴上,博主的职业类别在 x 轴上。每个气泡的大小(和不透明度)代表匹配该组合的帖子数。正如所料,流行病学领先,但相当多的帖子似乎使用 COVID 数据来展示其他东西,或以新的方式应用 R。

总结想法
我们鼓励您使用我们的闪亮应用程序亲自探索数据。如果你想提交你的文章被收录,请填写这张谷歌表格。
正如我们在应用程序的页脚所提到的,R 社区是聪明的,并且产生有趣的内容,但是当涉及到新冠肺炎时,并不是我们所有人都是专家。参与这些帖子会让你更好地理解 R 在我们当前时刻的应用,也许还能给帖子作者提供反馈。我们不认可任何特定作者的发现,并鼓励您从声誉良好的来源如 CDC 和世卫组织找到准确、相关和最新的信息。
新冠肺炎在股票市场上横冲直撞。机器学习来解释。
亨尼投资
使用机器学习来识别新冠肺炎期间受打击最大的股票中的共同因素。

在这篇文章中,我使用机器学习来研究那些在新冠肺炎期间股价下跌最多的公司。为了更好地说明发生了什么,让我们来看看最近市场最动荡时期的标准普尔 500 指数。

这场新冠肺炎崩盘结束了长达十年的牛市,股价在 2020 年 2 月 20 日至 3 月 23 日期间下跌了 33% 。虽然这次衰退对股票市场有整体的负面影响,但并不是所有的公司都受到同样的影响。下面是 1500+ 美国上市公司在此期间的股票市场回报率分布。

在 X 轴上,我显示了 2020 年 2 月 20 日至 2020 年 3 月 23 日之间的价格增长。在 Y 轴上,我显示了报告增长的公司的百分比。
我们可以看到大多数公司出现负增长。分布看起来正态,平均值在 -33% 左右,在正回报范围内有一些异常值。这与我在这里提到的正常市场条件非常不同:
这种环境为投资者提供了一个研究不同公司形象如何受到影响的绝佳机会。特别是,哪些类型的公司相对于那些完全没有受到影响的公司受到的打击最大。随着机器学习为我们所用,我将数据科学家的观点带入游戏,分享我对这次衰退教会我们什么的观察。
财务数据
在这项研究中,我使用来自 www.vhinny.com的 Alpha 数据集,它提供了过去 8 年的基本财务数据,包括资产负债表、损益表和现金流量表。我还使用免费的 alpha vantage API 来访问每日股票价格。
问题陈述
在这项研究中,我希望找出那些受打击最大的公司背后的驱动因素。根据上面的直方图,我对股价至少损失了 55% 的公司感兴趣,这适用于数据中所有公司的 ~20% 。
方法学
有许多方法可以解决这个问题,从无监督聚类到预测建模。我在这里使用的方法利用了预测建模的优势。我的目标不是训练一个预测未来衰退的模型。相反,我的目标是了解过去。带着这个目标,我发现简单的决策树分解是这项工作的最佳方法。
决策树因过度拟合训练数据而臭名昭著。由于这一特性,它们几乎从未用于预测建模,从而产生了随机森林和 XGBoost 。然而,与其他算法不同的是,决策树提供了对其决策过程的准确可见性,向研究人员准确显示了决策是如何做出的。
我把这个问题框定为一个分类任务,把价格损失至少 55%的公司列为正面例子。然后,我用以下参数拟合一个决策树(实现代码可以在这里找到):
- 最大深度:10
- 叶子上的最小样本:5
- 最大叶节点数:10
因为我的目标是解释过去而不是预测未来,所以我没有像在典型的预测机器学习问题中那样分成训练和验证。我用的参数并不是区分正反例的最佳参数。相反,我选择的参数将问题限制在可以容易解释的维度。这样,在稍微牺牲性能的情况下,我可以确定并可视化数据中的基本趋势,这正是我所寻找的。
实施情况和结果
下图显示了一个决策树,适用于识别在新冠肺炎危机期间股价损失至少 55%的公司。

这个决策树适合于 1500 多家美国上市公司的基本财务数据。每个节点都有一个标签(类),根据叶子上的大多数例子将叶子分类为正或负。我使用红-白-蓝的配色方案来帮助视觉化每个节点上积极和消极的平衡。纯红色表示绝大多数例子都是正面的。纯蓝色表示大多数示例都是负面的。随着正反例子的比例达到相等,颜色变得更加淡化。如果正样本的数量等于负样本的数量,节点将变成白色(完全透明)。箭头表示基于节点本身记录的条件的分割。左箭头将符合条件的例子分开,不符合条件的例子留给右箭头。
全球趋势

根节点包含整个数据集。它被标记为负的,因为大多数例子(1223)是负的(和 275 个正的例子)。这个节点上的分割是基于价格对有形资产比率完成的,这是价值投资者中的一个流行指标。如果有形资产的价格比大比 0.88 大,公司被标记为负面,将我们带到右下方的节点。这种情况对我们来说轻而易举,因为它使我们达到了 91%的公司被正确标记为负面的水平,在(694 + 73)中有 694 家。如果不满足这个条件,我们就转到左边的节点,这样我们就有许多潜在的目的地和可能性要考虑。
积极的暗示

虽然树的全局右分支帮助我确定了绝大多数的负面例子,但我希望在左分支找到一条通向正面例子的道路。通往正面例子的最短路径让我有了三个条件:
- 有形资产价格比≤ 0.88
- 运营资本的变化> 1 . 15 亿美元
- 资产回报率≤ -0.07
用语言来说,公司必须相当便宜(条件 1),以低于其有形资产成本的价格出售,并在最近一个财政年度报告亏损(条件 3)。第二个条件更难解释,因为它取决于企业的规模,但它表明公司的资产负债表有所改善。
更深入

从根向下进入左分支 7 层后,我发现自己处于一个白色节点,该节点使用价格、收入和有形资产有效地将公司分为正面和负面。重要的是要注意,白色节点上的示例不是随机采样的示例,而是满足 6 个条件的示例导致白色节点。
在这个节点上,几乎所有价格对收入 > 1.8 的公司(17 家中的 16 家)都是负数。这些是价格适中的公司,它们在上一年亏损了一些钱,但并不太贵,因为它们的交易价格低于其有形资产的价值(基于达到白色节点之前的拆分历史)。
或者,交易价格与收入之比(T10)≤1.8 和交易价格与有形资产之比(T12)≤0.04 的公司大多为正(47 家中有 37 家)。这是那种离破产只有一步之遥的公司。岌岌可危的是,他们业务的价格几乎是他们年收入的两倍,他们账面上所有有形资产的价值不到 1 美元的 5 美分。以任何标准衡量,这种不稳定的基础都可能会让投资者抛售股票,希望减少损失,并进一步压低股价,以反映这些公司的内在价值。
结论
在这篇文章中,我对 1500 多家美国上市公司的财务状况进行了分析,以确定由于 T4 新冠肺炎 T5 恐慌导致 T2 股价下跌 55%的公司的趋势。2020 年 2 月 20 日至 3 月 23 日期间,美国公司的股价平均下跌了 33 %。亏损 55%+ 的公司有着臭名昭著的糟糕的财务表现,这部分反映在它们的价格甚至在崩盘开始前就一直低于其有形资产价值。这些公司中输家的一个特征指标是那些以有形资产的 4%或更低价格出售的公司。另一个不太严重的特征是,公司损失了 55%以上的价格,这是他们上一个财政年度报告的损失。在估值已经很低的情况下,上一财年的财务损失导致投资者卖出他们投资组合中的失败者 T21。
感谢阅读我的文章!如果你喜欢,你可能想看看这个:
使用机器学习来识别新冠肺炎崩盘后恢复正常的股票中的共同因素。
towardsdatascience.com](/stocks-that-recovered-from-covid-19-machine-learning-comes-to-explain-ba712f62456d)
我们连线吧!
我很高兴和与我志同道合的人联系,这是我对财务独立的追求。如果你也在寻求经济独立,或者你想合作,交流想法,请随时联系我们!以下是一些可以找到我的地方:
- www.vhinny.com—投资研究平台,为您自己的分析提供金融数据
- https://www.linkedin.com/company/vhinny——加入我们 LinkedIn 上的社区,在那里我和其他贡献者分享投资相关的内容
干杯!
新冠肺炎研究:我们前进得太快了吗?
获得平衡
编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
已经有大量重要的新冠肺炎研究进入公共领域,包括旨在计算病例死亡率、新治疗的有效性、风险概况和缓解策略有效性的研究。人们可以理解为什么——人们对新型冠状病毒的信息有着贪得无厌的胃口和需求,不仅承诺对该主题的任何研究结果进行大量宣传,而且希望这种研究能够通过帮助确定对这种疫情的最佳反应,立即改变人们的生活。也就是说,在传播新发现时需要一定程度的谨慎。
出版存在的问题
对于科学家来说,花上几个月甚至几年的时间,小心翼翼地将一个想法发展成一篇论文并不罕见,但我们看到越来越多的例子表明,整个过程只需要几天时间。研究设计中的问题,如小样本和赢家诅咒、多重比较和选择性报告结果,往往助长了发表“性感”研究结果的偏见,这一直是许多讨论的来源。有少数例外,但这通常是错误信息加上认知偏差的结果,如确认偏差,我们都容易受到影响(例如,我们倾向于只看到我们想看到的证据),而不是任何渎职行为。还有迹象表明,所有学科的科学家都开始更加认真地对待这些问题。
然而,疫情加剧了上述问题,因为不仅研究人员急于撰写论文,而且期刊也急于通过加速同行评审过程发表论文。当然,尽快将一个重要课题的优秀科学成果公之于众是很重要的,但这确实会让本已不可预测的同行评审过程变得比以往更加嘈杂。虽然良好的科学是我们应对疫情的关键,但仓促开展和发表的研究有可能造成伤害。
潜在危害
例如,发表在 《柳叶刀》 上的一项研究,随后被撤回,该研究旨在表明羟氯喹远非最初希望的对新冠肺炎的成功治疗,实际上与风险增加有关。这导致世界卫生组织暂停了相关临床试验。提供本研究中使用的数据的公司缺乏透明度,导致了围绕结论可信度的许多问题——编辑在出版前很难(如果不是不可能)发现这些问题。尽管如此,似乎有理由认为,鉴于论文中许多明显的方法问题,它通常会在“正常”的同行审查过程中被一家老牌期刊拒绝。尽管如此,它还是被发表了,这被一些人用来破坏对科学的信任。
另一个例子是作为预印本发布给媒体的研究(这打开了另一组有问题的问题)。通过脸书 ads,作者招募了 3330 名居民样本,并对他们进行了新冠肺炎抗体测试。这是一项雄心勃勃和及时的研究,并认为其随后的分析表明,背景感染率远高于人们此前的想法。这反过来表明,死亡率可能大大低于以前的最佳估计。这些发现被美国保守派活动家作为反对封锁和其他缓解措施的证据。尽管其他科学家提出大量批评,指出这些发现很可能是各种统计误差来源的结果,但这种破坏还是发生了。另一个方法论障碍是选择偏差。虽然许多人可能希望进行抗体检测,但哪一组人可能会付出更大的努力(例如,前往检测地点等。)获取一个?可能是那些有充分理由怀疑自己或亲近的人感染了病毒的人。这意味着,不是测试圣克拉拉人口中的“代表性”样本的抗体,而是测试人口中的样本,从各方面考虑,这些样本更有可能首先被感染。值得注意的是,自 4 月 11 日发表以来,该论文已被引用 135 次,由此可见该领域研究的规模和快速性。
我的目的不是对任何特定的论文提出过分的批评,因为方法和抽样问题是常见的,观察数据中总是存在不确定性,而且没有完美的研究这样的事情。相反,我的目的是强调,虽然研究人员渴望做出积极贡献是可以理解的,但在没有花必要的时间仔细研究工作的情况下就突然拿出新的研究成果可能是有成本的。
伸得过远
另一个不太严重的例子是在 《每日电讯报》 中讨论的一篇文章,它暗示秃顶可以预测疾病的严重程度。这一论断的证据是对马德里医院的 122 名患者的研究,其中发现男性患者的背景脱发率比一般人群中相似年龄的男性的背景脱发率略高。
虽然我不能说秃顶不会成为疾病风险的预测因素,但我可以说的是,一项对 122 名患者的小规模观察研究没有提供任何证据。要知道为什么,我们必须考虑观察性研究的可变性。如果我观察 122 名患者中的任何一组,我很可能会发现他们在许多与疾病无关的因素上与一般人群不同。例如,他们可能睡得更多/更少,吃更多的加工肉类,喝更多的红酒或者可能喝更少的白酒。如果我确实发现了一个具有统计显著性的模式,除了第一个例子,提出一个“因果”解释来解释它与冠状病毒的相关性(例如红酒的药用特性)并不太困难,这就是问题的症结所在。
另一个相关的例子是许多研究(例如这里的和这里的)表明维生素 D 补充剂可能在控制疾病风险方面发挥重要作用。这些研究主要是比较欧盟各国的平均维生素 D 水平与新冠肺炎死亡率。有些与直觉相反的是,欧洲高纬度国家的维生素 D 水平较高,尽管 UVB 阳光照射较少,因为食品强化和补充更为普遍。在研究发表的时候(现在情况有所改变),低纬度国家如西班牙和意大利的新冠肺炎死亡率较高,平均维生素 D 水平也较低。与秃顶的例子相反,如果将来的临床试验表明维生素 D 至少在某种程度上是重要的,我不会感到惊讶,但我可以说的是,这种性质的研究没有提供任何真正的证据。这些国家的维生素 D 摄入量可能不同,但从人口密度、缓解策略、人口统计到冰淇淋消费,它们在其他所有方面都不同。
人们可能会合理地反驳说,尽管存在任何方法上的问题,但这些研究提供了支持性的、暗示性的或初步的证据,证明维生素 D、秃顶或以如此粗糙的方式检查的各种其他因素的重要性。他们没有,同样,新冠肺炎冰淇淋消费量和死亡率之间的显著相关性也没有提供任何证据来支持减少冰淇淋消费量可以降低死亡率的假设。
有人可能会合理地问这有什么危害,因为维生素 D 对你有好处。这在一定程度上是对的,但摄入过多会带来健康风险,如果我们可以想象一些人为了抵御冠状病毒而摄入毒药,那么就不难想象一些人摄入了过多的维生素 D 补充剂。
更一般地说,不考虑任何潜在的群体伤害,当这种性质的研究被授予出版物和媒体关注时,其他研究人员就更有可能认为这种方法是回答重要研究问题的一种可接受的方法,并效仿这种方法。
总之,所有学科背景的科学家在这次疫情中都脱颖而出。事实上,疫情突出了科学家工作的重要性。看到许多知识渊博的研究人员在为非常复杂的问题提供及时可靠的答案方面展示出令人难以置信的技能和创造力,令人鼓舞。然而,每个人都有责任确保,在渴望提供及时而重要的建议时,我们不会过多地牺牲准确性和可靠性。
当然,在疫情时代,迅速将新信息公之于众的好处,尤其是当目的是治愈或防止致命病毒传播时,可能会超过提供不太可靠信息的任何成本。尽管如此,并不是所有的研究都对管理疾病的风险至关重要,科学家需要尽最大努力确保这种平衡。
这篇博文最初出现在 LSE 英国政治与政策博客
新冠肺炎:地理区域被感染的风险
PostgreSQL-PostGIS 方法

图 1:曼哈顿出租车的轨迹
迈向数据科学 是一份以研究数据科学和机器学习为主的媒体刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
自从电晕疫情爆发以来,我一直看到多伦多技术社区的人们提出了令人敬畏的分析,如 Russell Pollari 为了人民的利益贡献他们的理解和知识。这一直是激励我尝试为我的硕士论文和研究工作寻找一些用例的因素。
在本文中,我将解释我是如何想出利用地理区域内的轨迹来了解哪些地区受新冠肺炎影响的风险更高的想法的,例如,多伦多或纽约。在我深入实际框架本身的细节之前,让我们先了解一些基础知识。
PostgreSQL 和 PostGIS
PostgreSQL (又名 Postgres)是一个开源的对象关系数据库管理系统(ORDBMS),强调可扩展性和标准遵从性。它扩展了 SQL 语言,并结合了许多安全存储和扩展最复杂的数据工作负载的功能。
PostGIS 是 Postgres 的空间数据库扩展器。它向 Postgres 添加了空间函数,如距离、面积、并集、交集和几何数据类型(这也是我在当前分析中使用它的原因)。
数据
我使用的数据集由纽约市出租车和豪华轿车委员会(TLC)发布,其中包括接送时间、地理坐标、乘客数量和其他几个特征。数据集 文件 包含 1,048,576 个旅行记录,这些记录包含作为(经度,纬度)坐标对的上下车点。为了这个实验的需要,我依靠随机样本 S 包括 10,000 双。对于每一对接送坐标,我利用 Google Directions API(python 代码 )在 NYC 创建轨迹(如图 1 所示)。
将地理区域划分成统一的网格
设轨迹 t = {(x_0,y_0),(x_1,y_1),…,(x_n,y_n)} 等于从起点到终点的路线,其中序列对 (x_i,y_i) 表示 2D 笛卡尔坐标系中的经纬度坐标。虽然移动物体的单个轨迹被定义在较低的粒度级别(例如,经度和纬度坐标对的序列),但是地理区域的分析通常需要在较高的粒度级别完成,例如在城市的街区或邮政编码级别。不失一般性,我采用了一个均匀网格的抽象,它将观察空间 A 分成一组均匀间隔的 r 行和 c 列,形成网格单元;行数不需要等于列数。我正式定义 grid_rc 如下:
grid_rc =

图 2:样本网格和网格单元上的样本轨迹
grid_rc 由 r x c 网格单元组成,而 c_ij 代表第 i 行和第j列的网格单元。通过将 A 划分为网格单元,我能够将轨迹 t ϵ T 从地理位置序列转换为 grid_rc 上的网格单元序列。例如,图 2 显示了一个 7x10 网格和一个穿过 13 个网格单元的样本轨迹,从 c_02 开始移动到 c_03、c_04、c_14、…,一直到 c_67。
现在你应该想到一个有趣的问题。为什么我需要将地理区域划分成网格单元?这可以从以下可视化中理解:

图 3:从作为地理位置的轨迹到作为网格单元的轨迹
因此,我们看到的是一个单一的(a)轨迹表示为地理位置(b)遍历网格单元和(c)最终转换为一组网格单元表示的运动路径的轨迹。对成千上万条轨迹进行的这种抽象使我们能够发现移动物体(即人、公共汽车和汽车)与分割的地理空间的相互作用。
请注意,网格的大小在更精确的分析和更快速的分析之间提供了一个有趣的平衡。这是因为网格的行数和列数越多,每个网格单元所代表的地理区域就越小,但代价是必须将每个轨迹关联到更大数量的网格单元,这在计算上是昂贵的(如图 4 所示)。

图 4 😦 a)更少和(b)更精细分析之间的权衡
数据库中数据集的建模
为了将数据存储在 postgres 数据库中,需要将其转换为众所周知的文本 (WKT)格式,这是一种用于在地图上表示矢量几何对象的文本标记语言。WKT 可以表示许多不同的几何对象,如点、线串&多边形等(如图 5 所示)。

图 5:几何图元(2D)[参考:https://tinyurl.com/nz8ybfu4
我使用 Linestring 存储轨迹数据集,类似地使用 Polygon 存储网格单元坐标。使用这个代码我将地理空间划分成 35×35 的网格(如图 6 所示)并以 WKT 格式存储网格单元坐标。

图 6:划分为 35x35 网格的地理区域
识别高感染区域
宣布地理区域(即网格单元)为高度感染的想法是基于这样的假设,即通过特定网格单元(划分的地理区域)的轨迹数量越多,该区域被感染的机会就越大。我通过绘制轨迹与网格单元的相互作用以及使用基于 PostGIS 的空间查询来识别这些区域。
查询
Q#1:存储网格单元坐标和轨迹数据集的查询
我使用 pgAdmin 中可用的导入/导出命令将数据存储在 traj、网格和单元格表中。现在是进行神奇查询的时候了,该查询可以找到感染风险高的区域。
问题 2:神奇的查询
神奇的部分是我们得到的表格(traj_as_cells)。它类似于图 7 所示,但是针对数千条轨迹。
完成上述分析后,我们的工作是找到通过其的轨迹数量最多的细胞 id,即,具有被新冠肺炎感染的高风险的(划分的地理区域)。
为了帮助更好地理解它,我们可以编写一个简单的查询来查找有多少轨迹通过单个网格单元(在下面的查询中 646 )。
问题 3:发现具有高感染风险的热点(网格细胞)
上面的网格细胞有 111 个轨迹穿过它(可能是感染的热点)。
(图 7)显示了从 postgres 数据库获取的快照。此外,我们可以通过将它的 id 与“单元格”表进行比较来定位这个网格单元格坐标(如 Q#4 所示)。

图 7
问题 4:定位网格单元坐标
最后,我们可以聚集轨迹穿过的所有网格单元,并基于穿过它们的轨迹的数量对它们进行排序。
寻找穿过每个网格单元的轨迹
上面的代码聚集了通过每个网格单元的所有轨迹,并将它们存储在traj_ids.txt文件中。最后,我们使用一个 bash 命令对网格单元进行排序。
perl -ne 'push [@a](http://twitter.com/a), $_; END{ print sort { length $a <=> length $b } [@a](http://twitter.com/a) }' traj_ids.txt
概述
- 我们开始探索一个地理空间,并着眼于人的运动路径,即轨迹。
- 我们将地理空间划分为统一的网格单元,并讨论了较小或较大网格大小之间的权衡。
- 此外,我们详细阐述了划分地理空间如何使我们能够将轨迹从一组地理位置坐标转换到一组网格单元中。
- 最后,我们执行了各种 Postgres/PostGIS 查询来查找轨迹穿过的格网单元。
- 最后,python (numpy ,pandas )使我们能够将属于每个单元的轨迹放在一起,并通过 bash 命令对它们进行排序。
结论
从本质上说,这项工作提供了一个简单、易于遵循的概念验证方法,用于发现受新冠肺炎影响的高风险地区。
新冠肺炎情绪分析系列,第 1 部分:开始

🇨🇭·克劳迪奥·施瓦茨| @purzlbaum 在 Unsplash 上拍摄的照片
推特情感分析
理解一级防范禁闭中的伦敦人
我发现封锁最令人震惊的是,与朋友聚会喝酒,或在某人的电脑前与同事交谈时,社区的丧失。
于是,我们失去了对每个人的感觉,失去了被倾听的感觉,失去了将社会团结在一起的共同声音。
我想通过 Twitter 了解伦敦人对事件的反应,以某种小的方式抵消这一点。我们对谁有好感?又是什么给我们带来了愤怒和挫败感?

这将是一个由 3 部分组成的系列,我们将会看到解决这个问题的几种方法…
第一部分:入门:如何获得你的推文,如何为推文评分,进行一些高层次的相关性分析。
第二部分:假设检验:如何在统计上高度确认组织情感上的信心差异,使用文字云来了解公众对某人的真实看法!
第 3 部分:建模:展示如何逐步应用频率主义和贝叶斯方法来建模锁定的赢家和输家,我还将清楚地概述每种方法在回答这个问题时为我们提供了什么。
第 1 部分:入门
获取推文:
我试图使用 Twitter API 来检索关于该病毒的推文,但是,搜索 API 将历史呼叫限制为 7 天,幸运的是,我找到了一个名为 GetOldTweets3 的 Python Twitter scraper,它帮助我解决了这个问题:
GetOldTweets3:当函数被调用时,日期和搜索字符串保持可配置
我发现在抓取 Twitter 时存在稳定性问题,导致当我达到 Twitter 配额时出现“HTTP 错误 429:太多请求”,或者当我与他们的服务器失去连接时出现“HTTP 错误 503:服务暂时不可用”。
这两个错误都会导致收集到的数据丢失,所以 try/except is your friend …在这些异常的情况下,我要求函数在重试之前等待 15 分钟,并确保我为用户打印了大量的进度更新…包括函数超时时的计时器…
第 1 次尝试(共 3 次)检索 2020–05–30
在 HTTP 请求期间发生错误:HTTP 错误 429:请求太多第 1 次尝试(共 3 次)检索 2020–05–30 时出错。睡了 15 分钟。
分钟睡眠:
0..一..2..3..四..5..6..七..8..9..10..11..12..
在撰写本文时,我在 3 个月的时间里收集了伦敦人以“冠状病毒或 covid 或新冠肺炎或 covid19”为搜索字符串的 55 万条推文,并将其作为每日 csv 文件保存在我的 GitHub 中。
解析文本:
我们想提取伦敦人在推特上谈论的人/事,这样我们就能找到情绪的主要驱动因素…
我尝试了一下 spaCy 的 NLP 管道:
首先使用词性标注器来检索专有名词(虽然它工作得很好,但我发现这不符合我的目标,因为它检索了许多非实体)。
然后使用实体识别器来检索预训练管道识别为“人”或“组织”的任何东西。
然后(出于兴趣)我用 EntityRuler 覆盖了带有我自己的自定义列表的实体识别(我看了两个:Boris Johnson 和 NHS)。
尽管 EntityRuler 是最精确的,但它非常繁琐,需要为每个实体手动设置规则,所以我选择了实体识别器:
spaCy 的 NLP 管道:将实体识别器应用于一列 tweets
得分情绪
我特别使用了 VADER (Valence Aware 字典和情感推理器)Python 库,因为它已经被调整来处理社交媒体上表达的情感。它结合了词典方法和基于规则的方法,在社交媒体上进行情感评分时提供了高水平的准确性。
他们的 GitHub 提供了 VADER 研究论文的更多细节,但总结起来:
词汇法:
- 情感评分从-4(非常负面)到+4(非常正面)不等,收集了 10 位独立评委的 9000 多字,他们自己也经历了审查过程。
- 平均评分为 0 或评分标准偏差> 2.5 的功能被丢弃,留给我们一个包含 7,500 个已验证功能的词典。
VADER 不仅研究了单个单词的情感等级,还研究了句法对句子层次情感的影响…
基于规则的方法:
- 例如,“好”与“非常好”是程度修饰语“非常”增加句子中情感强度的一个例子。
- VADER 方面已经制定了一些规则,来检测此类结构性因素,并根据经验对整体情绪进行加权。
代码实现起来非常简单:初始化 SentimentIntensityAnalyzer()类,然后应用 polarity_scores()方法(这是我在 map 函数中做的)。这返回了一个数组,其中包含每条 tweet 的 4 个不同的情感指标:POS,COMPOUND,NEU,NEG。
3 个分数(POS/NEU/否定)量化了该推文中包含 POS/NEU/否定单词的比例(例如,POS =推文中的正面单词数/推文中的总单词数)。
然而,我决定在下面的分析中使用化合物(或化合价),因为它简洁地解释了两极的极性程度:正极和负极。相对于该文本的长度,它还被归一化为-1 到+1 之间的值(+1 表示最大正值,-1 表示最大负值),从而可以用作比较度量。研究人员通常将得分> 0.05 分为积极,并且
Correlation: Did sentiment vary with the spread of the virus?
I found a dataset on Kaggle that had collated Public Health England’s statistics on the cases and deaths from Coronavirus. I started to plot this in Matplotlib together with the average daily sentiment observed from the tweets:

Plotted: Negative Sentiment and Cases / Deaths
I learned a couple of things from seeing the data like this:
- A.B.C .(总是在检查)
在这一时期的开始,我注意到我收集的推文数量急剧减少,很快发现我的查询已经过时……
-不要搜索标签,而是搜索文本,因为大多数推文不经常使用标签。
——“COVID”取代了“冠状病毒”,成为频繁发微博者的便捷速记。
因此,将搜索字符串更改为“冠状病毒或 covid 或新冠肺炎或 covid 19”可以立即看到改进(见 5 月)。尽管如此,谢天谢地我还是有足够大的样本量。 - 高水平的数据产生低水平的洞察力
在如此高的聚合水平上,情绪通常围绕全球平均水平波动。
随着病毒的发展,我们是否看到了更多负面的推文?
是的,我们可以大致看到这一点。
例如,情绪(即复合得分)与每日死亡数的负相关性为-41%。当你给死亡人数加上一天的滞后时,这个数字增加到-50%,表明人们对前一天的消息可能有一些延迟反应。

在相关性的一些早期不稳定性之后,我们能够看到一些有趣的东西:

关联历史:负面推文与每日死亡人数
这种相关性在 3 月和 4 月基本上是负的,即“病例数/死亡数的增加(更为积极)与整体情绪的恶化(更为消极)相一致。“这也是我们在观察情绪和病例/死亡趋势时看到的情况。
自那以后,这种相关性变成了积极的,即使每天的死亡人数变得很少,人们的情绪也保持相对不变,这表明伦敦人现在已经找到了他们愤怒的其他原因。
结论
收集完数据后,我们现在准备更深入地了解伦敦人。
在下一篇文章中,我将会使用假设检验(并且会大量使用!)验证对不同组织的态度是否真的存在差异。我将展示如何设置测试,并解释我们在每个测试中所依赖的假设(以及如何测试这些假设)。
我们还将看到如何以 wordcloud 的形式可视化人们的真实意见…例如,我们将国民保健服务视为、【关心】、【支持】、【英雄】、【保护】、【乐于助人】 …但我们对政府的看法是一样的吗?#掌声鼓励者对此有什么影响?
《T4》第二部再见……
新冠肺炎情感分析系列,第 2 部分:假设检验

Twitter 情感分析/假设检验
理解一级防范禁闭中的伦敦人
在这个系列中,我们将利用伦敦人的推文来了解情绪在新冠肺炎封锁中是如何演变的,以及在他们眼中哪些公众人物和企业是赢家和输家。
在第 1 部分:“入门”中,我们使用实体识别和情感评分获得了 Twitter 数据并对其进行了处理。
今天,在第 2 部分中,我们将查看数据,并通过假设检验来验证不同实体的情感得分存在 统计显著性 差异。但是首先…
奠定基础
支撑假设检验的是以下思维过程:
- 正态分布:我们承认我们不可能捕捉到这段时间发送的所有推文,所以我们拥有的数据点是从更广泛的人群中获取的样本。如果这种抽样是随机的,除非样本大小为< ~30,否则根据中心极限定理 ,您可以预期您的测量观察(在这种情况下,我们正在测量情绪)是正态分布的。例如,如果我们的样本均值为 5,则假设分布为:

正态分布,样本均值= 5
2。设置测试:为了测试这个样本均值是否不同于另一个样本均值(假设是 2,但它可以是任何数字),我们将计算多少个标准偏差(或者,在抽样统计中,标准误差)会将两者分开,如果它们是同一分布的一部分。也就是说,我们假设它们不是来自不同的情绪分布,而是来自相同的分布:

3。标准化标准:想象这个操作,我们正在做的是沿着 x 轴将正态分布移动-2,然后除以标准误差。它成为以 2 为中心的标准正态分布,等式可以改写为:

我还概括了一些术语,以突出正在进行的假设检验
- z-score 量化了替代假设距离新均值有多少标准误差(在这种情况下,这是零假设)。这很强大,因为标准正态分布上任何 z 得分的 p 值都是已知的。因此,我们能够描述从与空值相同的人口分布中观察到替代的可能性。然后,我们将能够拒绝或接受我们的零假设,即通过比较这个 p 值和我们的显著性水平(我们将坚持 0.05 的显著性水平),备选项被绘制为与零相同的分布。
3.学生的 t 分布。在下面的测试中,我们将把 z 分数称为一个 t 统计量。这是因为我们将假设一个学生的 t 分布,它比标准正态分布有更厚的尾部,从而引入一些保守性来应对类型 I 错误,这是因为我们的观察值数量有限:

- 这个分布的 p 值也是已知的。
让我们继续我们的测试…
假设 1:政府 vs 国民保健服务

照片由 Grooveland 设计在 Unsplash 上拍摄
我们首先来看两个将在数据中得到充分体现的实体:政府和国民保健服务系统。

直方图:情绪
国民保健服务的情绪似乎更积极,分布更偏向右侧,我们可以通过查看平均值来确认这一点:
Avg Gov sentiment -0.036
Avg NHS sentiment 0.171
你可能想知道为什么 NHS 的直方图在 0.5 左右有第二个峰值。我以为这些是重复的推文,然而,发现它们得分相同,因为它们都使用了短语“谢谢”,例如…
谢谢#掌声鼓励者#掌声鼓励者# NHS #关键员工#一级防范禁闭#迪士尼乐园巴黎#迪士尼世界#迪士尼#明天将是美好的一天# ColonelTomMoore #冠状病毒
非常感谢 hollandandbarret & @ ray _ electronica 今天的复活节彩蛋捐赠@圣乔治医院# NHS # NHS workers # LondonNHS # front line NHS # medical team # stayat home #冠状病毒…
谢谢 NHS biglove NHS # thankyounhs # clapping fornhs # covid 19 # we einittother # stayat home # bandanavixenv @ sur biton,伦敦
假设:
- 每个分布的标准差是相同的。上面的箱线图通过比较四分位数范围帮助我们直观地证实了这一点:

紫罗兰图(左)和箱线图(右)
我们还使用 NumPy 证实了这一点:
StDev of Gov sentiment: 0.508
StDev of NHS sentiment: 0.527
确认这一假设的有效性使我们能够使用混合方差方法,因此 SciPy 的 2 样本 t 检验的实施可以归结为:
如果标准差不同,我们会使用韦尔奇的 t 检验来计算两个样本的标准差。实际上,这意味着只需设置 equal_var =False。
结果:
Ttest_indResult(statistic=43.62708002444751, pvalue=0.0)
回忆样本意味着我们正在比较…
Avg Gov sentiment -0.036
Avg NHS sentiment 0.171
p 值~0 告诉我们,以-0.036 为中心的学生 t 分布极不可能包含 0.171 的观察值。换句话说,上面计算的测试统计表明,平均值 0.171 与平均值-0.036 相差 43 个标准误差
判决:拒绝无效。我们可以很有信心地说,人们对国民保健制度的看法比对政府的看法更好。
情绪何时开始出现分歧?
我们看到整个 3 个月期间的平均情绪有所不同,但这是从什么时候开始出现分歧的?
我们可以绘制平均情绪的每日差异,但是,我们需要调整样本大小和每天数据的标准偏差,以衡量我们对每日样本均值的信心。
相反,我们可以为平均情绪的每日差异计算 95%的置信区间,这将我们的信心纳入我们的采样过程:我们创建一个上限和一个下限,我们有 95%的信心包含当天平均情绪的真实差异。

每条垂直的黑线都是为那一天构建的置信区间。每天的置信区间标志着我们有 95%的信心认为政府和国民保健服务的情绪存在真正差异的区域(因为当然我们的数据本质上只是总体人口的样本)。
在观察期开始时,每天发的推文相对较少。这些小的每日样本量导致了较大的标准误差,因为:

因此置信区间更宽。随着时间的推移,每日样本量增加,使我们的置信区间变窄。
信心区间在很大程度上完全低于红色零虚线,表明在整个期间,对政府的平均情绪低于对国民保健服务的平均情绪的信心为 95%。有一些罕见的时刻,如 4 月底,当区间越过零线时…在那些日子里,我们不能说我们选择的信心水平是政府情绪低于国民保健服务。
假设 2:政府 vs NHS…积极还是消极的感觉?
我们看到平均情绪有所不同,但这是因为对国民保健服务更积极(复合> 0.05),还是对政府更消极(复合< -0.05)?
Visually it appears both statements could be true, but we will test for this:

Distplot comparison using Seaborn
积极推文:
比率的差异是 0.159,即。NHS 的正面推文比例比政府高 0.159。
Difference in (Positive Tweets / Total Tweets): 0.15881778668707092
我们可以通过运行“两个比例的差异测试”来测试这种差异的统计显著性,这同样依赖于计算两个比例来自相同分布的假设的 t 统计量:

其中,比例差的标准误差为:

因此,我们可以轻松地手动计算 t-stat 和相关的 p 值:
t-statistic 47.33409611769171 p-value 0.0
判决:拒绝无效。另一个假设(NHS 的积极推文比率)距离零(政府的比率)47 个标准误差,p 值为 0,我们说这两者极不可能来自同一人群。
负面推文:
我们重复对负面推文的分析:
Difference in (Negative Tweets / Total Tweets): 0.14177193931000753
我们可以看到政府的负面推文比率比 NHS 的高 0.14,我们测试这一差异是否具有统计学意义:
t-statistic 38.561197004624 p-value 0.0
判决:拒绝 Null。与阳性率一样,差异有统计学意义。
或者,我们可以使用 Pandas crosstab 函数创建一个表,显示每个类别中的 tweets 数量。然后应用卡方检验来验证任何一行是否包含 pos、neu 或 neg 推文数量的不平衡:

交叉数据分析表
这返回:
-卡方统计量
-p 值
-自由度
-平均分布的预期频率
(1047.7937788707934,
2.981754146928481e-228,
2,
array([[6978.92922191, 3234.01294658, 9538.05783151],
[6640.07077809, 3076.98705342, 9074.94216849]]))
我们可以从中看出,无论是正面还是负面,推文的分布与平均分布相比是不平衡的。
假设 3:政府 vs NHS…伦敦人的意见有分歧吗?
是不是有些用户在推特上对国民医疗服务体系持更积极的态度,而另一些用户则更消极地指出伦敦人之间的分歧?或者这种对 NHS 的赞同观点在个人用户层面上也是正确的,因此我们每个人都持有这种观点?
这也是一个需要设置的简单测试,称为成对均值测试,我们从再次使用 Pandas crosstab 来创建平均情绪的用户级视图开始:

与其他参数检验一样,我们依赖于感兴趣变量分布的正态性假设(在本例中为差异栏),我们可以看到这大致成立:

差异列的直方图和 QQ 图
我们使用相同的框架来计算 t 统计量:

除了现在替代假设是差异的平均值列,零假设是没有总体差异(即,零),并且与假设 1(其是 2 样本均值测试)一样,标准误差是通过缩放标准偏差(这次是差异)来计算的:

或者简单地使用 SciPy:
Ttest_relResult(statistic=-9.035954747008454, pvalue=3.4616270088977246e-19)
判决:拒绝无效。即使在个人用户层面,我们也察觉到对政府和国民医疗服务体系的不同看法。看来我们在持有这些不同的观点上没有分歧。
注意:我们不需要正态假设就能对此进行测试,成对均值测试的非参数模拟( Wilcoxon 符号秩 测试)可用于查看中位数,而非均值:
WilcoxonResult(statistic=934184.0, pvalue=1.2233021976129815e-18)
判决:同样的结果。
为什么对 NHS 的看法更积极?
虽然我们现在知道公众对 NHS 的情绪比政府更热情,但很难辨别当公众对一个和另一个进行思考时到底激起了什么情绪。我们可以使用单词云来可视化使用了哪些单词:

我们并不更清楚,因为图片模糊不清,因为最频繁出现的单词是中性的,对化合价没有贡献。我们需要从政府和国民保健服务语料库中筛选出最具情感性的词语:

我们现在对为什么国民保健服务比政府更受欢迎有了更清晰的认识:
政府:推特用户在强调感知失败时更多地提到政府,而不是 NHS:
- 危机、失败、死亡、消亡、脆弱、停止、失败、严重、缺乏、紧急、困难、警告、失败
NHS: 推特通常称 NHS 为英雄,因为他们在如此艰难的情况下给予了支持和照顾。
- 感谢,关心,支持,嗯,帮助,安全,好,保护,爱,帮助,希望,朋友,英雄,自豪,伟大
因此,有趣的是,尽管表面上朝着一个共同的目标努力,但公众似乎认为 NHS 比政府打得更好。
随着时间的推移,国民保健服务的情绪:
随着时间的推移,这种国民保健服务的情绪是如何演变的?公众是逐渐喜欢上了 NHS,还是开始产生了积极疲劳?

(注意:你在 5 月份看到的 num_tweets 的增加是由于我在 第一部分 中提到的我的 Twitter 查询的改进,考虑到这一点,我们仍然可以提出以下几点)
在 3 月底/4 月初,有 3 个明显的每周峰值,最明显的是在推文数量上,但在复合情绪得分上也很明显,这与#ClapforCarers 活动的开始相吻合。
虽然此时对 NHS 的情绪受到了积极的影响,但这些每周的高峰已经基本消退,也许伦敦人已经感觉到#职业疲劳?
摘要
我们已经展示了如何应用假设检验来对 Twitter 情感数据进行统计上稳健的推断。我们已经展示了不同类型的假设检验如何有助于揭示情绪差异的本质,概括如下:
- 假设 1: 比较样本均值的双样本 t 检验,使我们能够得出 Gov 与 NHS 情绪平均存在差异的结论。我们还绘制了置信区间来跟踪这一点是如何随着时间的推移而演变的。
- 假设 2: 双样本比例差异 t 检验证实了这种高水平的差异是由对国民保健服务的更多积极态度和对政府的更多消极态度共同驱动的。
- 假设 3: 一个成对均值 t 检验告诉我们,用户在这方面没有分裂,即。这种 Gov 与 NHS 情绪上的分歧也存在于个人用户层面。
- 形象化:我们使用文字云来发现哪些情绪化的词语被用来描述政府和国民保健服务系统,以进一步了解公众的真实想法。我们甚至展示了#掌声鼓励者对国民保健服务热情的影响。
在这一系列的下一篇(也是最后一篇)博客中,我们将撒开网去寻找更多锁定期的赢家和输家。我们将一步一步地深入机器学习领域,开发有趣的方法来解决这个问题…
- 我们将从重复 word cloud/假设检验技巧开始,寻找新的赢家和输家。
- 然后,我们将看看如何通过使用逻辑回归模型来简化这一过程,以给出一个整体视图。
- 最后,我将解释如何以及,重要的是,为什么贝叶斯方法可以帮助我们跟踪一个城市不断变化的情绪。
《T4》第三部再见……
新冠肺炎情感分析系列,第 3 部分:贝叶斯情感分析

彼得罗·兰帕索在 Unsplash 上的照片
推特情感分析/贝叶斯推理
理解一级防范禁闭中的伦敦人
编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
在这个系列中,我们一直在使用伦敦人的推特来了解情绪在新冠肺炎封锁中是如何演变的,以及在他们眼中哪些公众人物和企业是赢家和输家。
在第 1 部分:“入门”中,我们获得了 Twitter 数据,并使用实体识别和情感评分对其进行了处理。
在第二部分:“假设检验”中,我们使用了各种不同类型的假设检验,解释了为什么对国民保健服务的看法比对政府的看法积极得多。
今天,在第三部分(也是最后一部分),我们将扩大搜索范围,寻找更多锁定的赢家和输家:
- 简单的方法:我们将从简单而繁琐的方法开始:我们重复第 2 部分的技巧,使用文字云和假设检验来突出显示,然后推断谁是赢家和输家。
- Frequentist 建模:然后,我们将看看如何通过使用逻辑回归模型来简化这一过程,以给出一个整体视图。
- 贝叶斯更新:最后,我将解释如何以及重要的是为什么贝叶斯方法可以帮助我们跟踪一个城市不断变化的情绪,我们将可视化结果:
使用贝叶斯推理对凯尔·斯塔默的情感建模
简单的方法
回到我们在第二部分“假设检验”中离开的地方,让我们从可视化我们的 tweets 数据集中最常提到的组织开始。我们还缩小了搜索范围,只搜索那些被评为正面或负面的推文,因为我们对找出赢家和输家感兴趣:

我们可以清楚地看到,亚马逊和财政部是最常被提及的组织。然而,很难看到这两个以外的东西,因为词云充斥着大写单词,被 spaCy 错误地标记为实体。
尽管如此,我们仍然可以看看亚马逊,然后说:
由于伦敦人在封锁期间转向网上购物,亚马逊将成为大赢家。
进行单样本测试来表明亚马逊的情绪得分是积极的是不够的,我们需要表明亚马逊的得分比合理的基线更积极。为此,我们将进行两个双样本均值 t 检验:
假设 1: 亚马逊情绪在封锁前的基础上有所改善。
假设 2: 在所有实体中,处于锁定状态的亚马逊情绪高于基线平均值。
假设 1:亚马逊对亚马逊
我们可以非常容易地创建两个发行版: amazon_prelockdown 和 amazon_postlockdown ,并运行 SciPy 的 t-test:
Ttest_indResult(statistic=0.10878616367025529, pvalue=0.9134795533240211)
这向我们表明,总体平均值的任何差异在统计上并不显著。为什么?
Number of pre_lockdown Amazon tweets = 3
Number of post_lockdown Amazon tweets = 201
因为我们的数据只有 3 条提到亚马逊的预锁定推文,导致标准错误太高,无法拒绝 null。
假设 2:亚马逊与其他公司
类似地创建相关的分布,并运行相同的 t-test:
Ttest_indResult(statistic=2.469890113757005, pvalue=0.01351783280956628)
我们有一个低 p 值,这将导致我们拒绝零,但是让我们检查分布和样本大小,以检查正态假设是否成立,因为我们已经执行了参数统计测试:

亚马逊与其他公司:分销
Amazon sample size 243
Other entities sample size 94912
我们在这里可以看到两个问题:
- 亚马逊分布看起来很奇怪,因为它有两个峰值,分别位于 x 轴的 0.2 和 0.6 处。运行一些快速 EDA,我们可以看到 0.6 的峰值需要纠正,因为它包含许多来自病毒式宣传活动的非独立推文:

教训:确保从现在开始删除所有重复的文本。
2.“其他实体”的样本量太大,无法代表我希望它能代表的基线。仅适用于其他组织。看来 SpaCy 错误地将大写单词标记为实体导致了这种分布被污染。因此允许这更接近地代表更广泛的样本集。我手动创建了最常提及的组织的良好子集,它们可以构成“其他实体”:
世卫组织、脸书、FDA、联合国、Whatsapp、乐购、英超、谷歌、FDA、苹果、疾控中心、议会、白宫

亚马逊与其他公司:发行版(已清理)
Amazon sample size 183
Other entities sample size 520
重新运行我们的 t 测试:
Ttest_indResult(statistic=1.1270992972809608, pvalue=0.26018755847340846)
我们现在不能拒绝零,因为:
- 删除重复的内容会删除 35 条推文,亚马逊的平均分也会从 0.15 降到 0.11
- 虽然“其他实体”的标准偏差变化不大,但由于限制了最常提及的组织,样本量大幅下降,标准误差从 0.0019 降至 0.02,因此降低了测试的统计功效。
本质上,如果我们想要确定亚马逊的正均值和其他公司的中性均值之间的差异在统计上是显著的,我们需要收集更多的样本来增加我们的测试拒绝零均值的能力。我们可以使用功耗分析来衡量这一点…
功率分析
为了以 95%的置信度得出两个样本均值确实不同的结论,我们需要多少条推文?
换句话说:要将第二类错误率降低到某个阈值以下,需要多大的样本量。我们将选择 20%的阈值,这相当于 80%的能力(正确拒绝空值的能力)。
我们可以进行一个功率分析(细节我们不在此赘述),但是代码非常简单,并且利用了 Statsmodel 的 TTestIndPower 函数:

效果大小= 0.13 的功效分析
这表明我们的测试需要几乎 1000 条 tweets 的非常大的样本量来正确拒绝 80%的空值。
因此,即使一个商业实体(亚马逊)与所有其他关于商业实体的最多推文进行了相对大量的测试,仍然没有给我们足够的统计能力来区分他们的手段。
然而,我们从单样本测试中得知,我们相信对亚马逊的看法是积极的:
Ttest_1sampResult(statistic=4.298040028883434, pvalue=2.616546144158821e-05)
所以 2 个样本的测试没有足够的统计能力,而单独观察每个实体就可以了。
然后,我们如何在所有实体中呈现这种单样本视图,以查看哪些实体确实是赢家/输家,而不必单独对每个实体重新进行 t 检验?
频繁主义建模
为了做到这一点,我们可以把这个问题重新组织成一个监督学习问题。我们可以应用 Statsmodel 的逻辑回归分类器预测两个标签类别阳性或阴性、中的一个,其特征是由 SpaCy 识别的组织。
我使用 scikit-learn 的tfidf 矢量器将实体编码到一个 features 数组中,使用其 TF-IDF 方法获得权重。我还使用这个函数来删除停用词和其他不需要的词,并将其限制在前 70 个特性中。返回的结果是:
逻辑回归结果
整个模型,特别是当只限于 70 个顶级特征时,无法预测一条推文是正面还是负面的(看 R)。然而,我们可以在个体特征层面学到很多东西:我们可以看到哪些是净正的(因为 coef > 0),哪些是净负的(coef < 0).
The model results also show us the certainty of our sample statistic (the coefficient) using: the standard-error for that distribution (influenced by sample size), the z-score and the p-value which both show whether this sample statistic was statistically significant, and then the 95% confidence interval for the sample statistic.
Winners:
- 科技公司。正系数和接近 0 的 p 值让我们毫不怀疑,亚马逊、苹果、Whatsapp、Instagram 等公司在推特上获得了正面评价。
- 英国政府的口号 stayhomesavelives ,也有一个非常积极的系数。沿着这些思路,自我隔离是另一个积极的故事,和社会距离。公众积极支持这些努力。
失败者:
- 多米尼克·卡明斯。极化图有一个非常负的系数。在围绕他决定打破社会距离规则的争议期间,这种情况显著恶化。
- 令人惊讶的是,Keir Starmer 的系数为负,这可能是由于对政府做法的批评吗?不,从数据来看,这实际上是因为人们批评他没有让政府承担足够大的责任。
- 由于推特指出了 NHS 医院的短缺,PPE 也被负面描述。
其他注意事项:
- 描述政府人物和部门的词通常具有较高的 p 值和跨越 0 阈值的宽置信区间,表明公众对其表现的看法不一。
结论:
我们已经使用频率统计创建了一个自上而下的方法来寻找好的和坏的情绪的组织驱动因素,但是这依赖于我们已经收集的 3 个月的数据。
在观察期开始时,情况发展很快,我们看到对一个实体的情绪波动很大,加上样本量较小,导致不确定性更大。这就是贝叶斯模型可以帮忙的地方…
贝叶斯的常客
在频率主义者的世界观中,我们有一个更广泛的人群,通过抽样,我们试图了解他们。因此,有一个真正的总体参数,通过抽样,我们可以通过我们的样本统计估计。
- 用这种方法,我们仍然试图得出一个单一的估计数。
- 通过这种方法,我们也允许我们的观点只被我们的观察期所了解,而不是被任何先验知识所了解。
在贝叶斯的世界观中,我们不认为有更广泛的人口。我们只有样品。然而,我们不得不承认,因为我们的样本量是有限的,所以我们的样本统计存在不确定性,所以我们应该将其建模为分布,而不是一个单一的数字。
- 通过这种方法,我们采用了一个预先的假设,并使用贝叶斯定理用新的观察来更新这个假设,从而得出当前的世界观。

贝叶斯定理
其中:
- P(p) =先验假设
- P(data|p) =新的观察值(如在 Frequentist 方法中),也称为似然函数
- P(p|data) =最新的(或:“后验”)假设,在我们用最新的观察结果更新了先验之后。
鉴于大多数数据收集的“实时”性质,特别是在新冠肺炎这样的独特事件之后,看看贝叶斯方法如何帮助我们回答这个问题是有意义的。
贝叶斯建模
让我们首先概述一下这种方法:
- 我们有两种选择来模拟贝叶斯定理的元素(如上):
- 共轭(如果可能的话,更简单和优选):如果先验是似然函数之前的共轭,则后验将是与先验相同类型的分布。这有利于使贝叶斯定理代数可解,后验(未知)参数用先验和似然(已知)参数表示。
- 抽样技术(例如马尔可夫链蒙特卡罗):有有限数量的共轭先验,如果我们的数据不符合其中任何一个,那么我们就需要使用抽样技术。
2.幸运的是,由于我们只对二元结果感兴趣(我们的推文要么是正面的,要么是负面的,因为我们将省略中性推文),我们可以使用最简单的共轭对来实现共轭:β二项式对**
- 似然函数:对一组推文进行采样,并将其标记为成功(正面)或失败(负面)是一种二项式分布:

二项分布
- 先验:贝塔分布描述了两个二元结果的概率范围:

贝塔分布
- 后验概率: …我们可以添加 n 次试验和 k 次成功来得出后验概率:

后验贝塔分布
这是一个漫长而复杂的等式,但从中可以得出一些重要的直觉:
- 二项式分布可以被认为仅仅是连续贝塔分布的离散形式。我们在上面证明的贝叶斯更新模拟了实际发生的情况:当新数据进来时,这通过二项式似然函数被表示为离散的数据点,其用于更新平滑的先验分布。
- α和β现在可以非常简单地用先验和似然性来表示:

应用
我们可以使用逻辑回归的输出来给出我们可以查看的最热门的实体列表。
为特定实体构建贝叶斯建模管道的过程可分为两个阶段:
- 先验:
-
统计在封锁前这段时间有多少正面和负面的推文:
-
使用此数据计算先验β分布的α和β:
2.后路:
- 使用公式记录新数据出现时α和β参数的变化:

我还在 Matplotlib 中创建了一个动画,可以向我们展示这种演变:
让我们来看看几个感兴趣的实体的情绪演变:
亚马逊
在此期间有 183 条推文提到亚马逊,橙色分布显示了封锁前情绪的概率分布,即。在那之前的两周。这是我们对亚马逊情感概率分布的先验信念。
这种情况下的分布非常平坦和浅,反映了这样一个事实,即只有相对较少的推文告知我们之前的信念:只有 2 条正面推文和 1 条负面推文。
一旦我们进入一级防范禁闭状态,我们就会用从一级防范禁闭期间收集的推文更新先验信息。这使我们能够对后半部分(蓝色)进行建模。请注意,随着时间的推移,随着我们收集更多的推文来通知我们的后验分布,分布如何变窄并达到峰值(由滑块表示)。
- 亚马逊的先验处于中性区域:0.5。但在封锁后几乎立即跳进了积极的领域,并停留在那里。
- 最终最大后验概率估计,即其中 0.6 的后峰显示亚马逊的情绪更可能是积极的(由 x 轴上的 1.0 分表示),而不是消极的(x 轴上的 0 分),这是基于我们发现的数据平衡来更新我们之前的信念。
凯尔·斯塔默
在封锁之前,我没有关于凯尔·斯塔默的推文来告知任何关于他的预先信念。在这里,您可以将α和β都设置为 0.5,因此采用 Jeffreys 的先验模型来模拟未知分布。先验呈 U 形。
在封锁期间,我们收集了 66 条推文,在整个期间,斯塔默的地图一直处于负值,徘徊在 0.2 左右。
Dominic Cummings
我们为多米尼克·卡明斯(Dominic Cummings)收集了 1003 条推文,在封锁前,他在我的数据集中除了积极的推文什么也没有。
在进入锁定期大约 20 天后,后验分布已经向左移动,地图结束时略低于 0.5。
这种从积极情绪到消极情绪的转变,从看实际日期,与围绕他打破社交距离规则的争议相吻合。
结论/最终想法
在这个博客系列中:我们展示了从 Twitter 建立一个 feed,应用一些文本处理,进行情感评分,并以一种明确赢家和输家的方式分析每个实体的情感是可能的。
假设检验:
我广泛地用这个来理解我的发现带来了一些统计上的清晰,这教会了我一些需要谨慎对待的领域:
- p 值:如果样本量足够大,可以确保足够低的标准误差,则可以很容易地使其具有统计显著性。问问自己你的测试是否具体到可以提出一个尖锐的问题?问问你自己你的过滤设置是否正确,确保你的样品没有膨胀。
- 正态假设:由于中心极限定理,这通常在大多数情况下成立,但我们总是可以使用我们假设检验的非参数版本,如 Mann-Whitney 或 Wilcoxon 符号秩检验。
- 均值回归/中和:对于任何足够大或不够具体的数据片段,情绪通常会聚集在 0 附近,没有意义。查看您的子样本的分布,如果它在 0 情绪有一个高峰,那么您可能需要更具体的过滤,以进行有意义的假设检验。
整体赢家/输家:
为了获得一个整体的观点,我使用逻辑回归来模拟正面和负面标签的推文,使用矢量化实体列作为预测矩阵。
这给出了一些有趣的结果:
- 总体 R 很低,这表明我需要比我包括的几个特征更多的特征,才能准确地模拟一条推文是正面还是负面。
- 然而,这不是我想要的…我感兴趣的是我包括的那些特征如何对积极或消极做出贡献,这可以从它们的系数中得到。与 scikit-learn 的软件包相比,使用 statsmodel 的软件包的好处是能够看到每个系数的统计置信度。
- 因为我们实际上对情感有一个不断进化的观点,所以我们转向了贝叶斯方法…
贝叶斯赢家/输家:
在这里,我设置了一个动画滑块来显示先验分布,然后随着新数据的到来,后验分布如何演变,这可以根据选择的实体进行配置。
- 这清楚地表明了卡明斯和 T2 的情绪是如何以及何时开始恶化的,并给出了一些很好的解释。如果我们在现场运行,我们的模型会给我们提供这种恶化的早期线索,我们就可以一条一条地跟踪推特了。
- 通过将概率分布附加到每个阶段的情绪,它也清楚地显示了我们的后验信念的确定性。
- 使用β-二项式模型极大地简化了参数,观察这种共轭性的一个好方法是二项式分布只是β分布的离散版本,因此简单地反映了单个新数据点到连续先验的增加。这在数学上被解决为通过添加二项式参数来更新β参数。
对于那些已经做到这一步的人,感谢您的阅读,当然欢迎并感谢所有的反馈,您可以在这里找到回购:
NLP 应用于最近的冠状病毒/ COVID19 推文:最近几周情绪进展如何?刮刮伦敦总部…
github.com](https://github.com/noahberhe/COVID-19)*
新冠肺炎模拟器
口罩如何有效减缓新冠肺炎的传播
编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
我们设计了一个新冠肺炎模拟器,在戴口罩和不戴口罩的不同场景下可视化病毒的传播。据透露,在 Unsplash 时,R0(每个感染者通常导致的二次感染数)可能会下降到< 1 (each infected person will infect less than 1 person in average), which strongly indicates that the virus spread could be significantly reduced.

Ultrastructural morphology exhibited by coronaviruses. Photo by CDC
自从 12 月 31 日在中国武汉报道首例病例以来,一种易感染的动物源性病毒 ovid-19 迅速席卷全球。在过去的 6 个月里,美国有超过 200 万人被感染,导致经济下滑和全国性的社会焦虑。根据美国劳工部的失业数据,从二月到四月,失业率从 4%飙升到 14 %, 1500 万人失业。
我们如何降低在公共活动中被感染的风险?尤其是我们已经看到了各州重新开放后的第二波疫情
CDC(疾病控制和预防中心)建议采取非常常规的预防措施:洗手、戴口罩和保持社交距离。这是我们从小就学到的老知识,但是这些程序能在多大程度上减少我们被感染的机会呢?在这里,我们开发了一个新冠肺炎模拟器来模拟病毒在室内环境中的传播,并比较了不同场景下新感染人数和新感染所需的最短时间: 1)不戴口罩,2)部分戴口罩,3)全部戴口罩。
模拟器设计
方案
人们在室内市场购物。市场只有一个入口/出口。市场中的人数(市场中的人数)是恒定的:一旦人们到达进入/退出,他们将退出,不会回来。与此同时,同样数量的新人将进入市场。假设随机有一个人感染了新冠肺炎病毒,他/她在购物时间只咳嗽/打喷嚏一次。我们想知道有多少新的人(R0)被这种最初的新冠肺炎携带者感染,以及第一个新的感染多快出现,以便评估口罩的有效性。
假设/近似

图。简化市场空间设计
- 市场被设计成一个矩阵
- 矩阵大小
- 每个细胞的大小是一个 6 英尺* 6 英尺的正方形(CDC 建议的社会距离)。整个市场有 10 * 10 个单元(总共 3600 平方英尺)。因此,市场可以模拟为一个 10 * 10 的矩阵(每个
对代表一个单元)。
- 如果人们在受感染的细胞内,不戴口罩的人将 100%被感染,而戴口罩的人被感染的几率会大大降低。
3。市场中的人数(市场容量)
- 沃尔玛和山姆会员店现在任何时候每 1000 平方英尺只允许五名顾客进入,这大约是商店容量的 20%。因此,模型中的容量范围将从 10 到 100。
4。从一个单元到另一个单元的行进速度
- 这是相当主观的,但是我们可以假设平均购物行程需要 40 分钟才能走完 0.5 英里,所以从一个单元走到另一个单元需要 0.1 分钟(6 英尺的距离)。换句话说,每一步/每一个动作需要 0.1 分钟。下一步有 8 个自由度:上,下,左,右,左上,直立,左下,垂直和停留。
5。新冠肺炎病毒变得无传染性所需的时间
- 典型房间和建筑物的换气率为6–10(一个空间内的空气在 60 分钟的时间段内被过滤或被新空气替换的速率)。因此,我们可以假设 10 分钟后,新冠肺炎病毒没有传染性。如果我们用步数来计算时间,需要 100 步新冠肺炎才会变得无传染性
编程语言
模拟器设计使用 Java。Python 用于数据分析和可视化。
模拟器设计
我们设计了三大类(空间、位置、人)和一个随机数发生器来实现模拟器的基本功能:初始化模型,跟踪每一步人的健康状况。简而言之,
- 类空间
Space(int size,int numOfPeople,int initialSick,int maskPercent,int maskSickPercent,int unMaskSickPercent) {…}
类别空间由 1)矩阵的大小,2)矩阵中的人数(市场容量),3)矩阵中的初始感染人数,4)戴口罩的人的百分比,5)如果戴口罩被感染的概率,以及 6)如果不戴口罩被感染的概率来初始化。
空间有几大功能,包括()和getHealthyPeople()跟踪感染和健康人的名单,以及next move**()更新每个人下一个位置的状态,如果有人到达出口,调用 离开
2。类别位置
Position(int row,int col) {…}
用行号和列号初始化类位置。每个职位都维护该职位的人员列表。它还具有 【添加人员】 (人员)离开* () 功能,用于从当前位置添加/删除人员。Helper 类定义了两个与位置相关的 helper 函数:getRandomPosition(int size)生成随机位置,以及get next Position(Position[][]matrix,int row,int col) 从当前位置基于随机方向得到下一个可能的位置。*
3。上课的人
Person(int id,boolean isSick,Mask mask) {…}
Person 类用 id (int,用于标识个人)、isSick (true 或 false)和 Mask status (enum YES 或 NO)初始化。它还有一个字段来记录一个人何时(在哪一步)生病(如果这个人是健康的,则为-1)。
4.枚举概率
枚举概率{是,否;…}
根据输入的概率,指定 1)戴口罩的人的概率,以及 2)当人们进入受影响的位置时被感染的概率。
数据分析和可视化
模拟输出
为了使输出更少偏差,对于每个数据点,我们重复模拟 1000 次,并使用中位数。我们通过调整空间模型的输入参数来评估不同场景中新感染的总人数和新感染所需的最少步骤:1)人数( numOfPeople )、2)最初感染的人数( initialSick )、3)戴口罩的人的百分比( maskPercent )、4)如果戴口罩被感染的概率( maskSickPercent )和 5)如果不戴口罩被感染的概率(
Space(int size,int numOfPeople,int initialSick,int maskPercent,int maskSickPercent,int unMaskSickPercent) {…}
输出文件是 csv 文件,“round”表示步数,“id”是人员 ID,“row”和“col”表示在矩阵中的位置,“timeStampIfSick”是此人被感染时的轮数(-1 表示此人未被感染),“stay”表示此人是否在市场中,“mask”表示此人是否戴口罩,颜色表示此人是否被感染(红色表示感染,绿色表示健康)。

图。模拟结果示例
新冠肺炎在市场上传播的可视化
如前所述,我们可以看到市场中人们的健康状况(感染和健康)。简而言之,我们将市场空间建模为一个 10 * 10 的矩阵,每个交叉点代表一个 6 英尺 6 英尺的区域。入口/出口位于(0,0),健康人用绿圈表示,感染者用红圈表示。受影响的区域被标记为一个更大的红色圆圈。在单个模拟中(市场容量为 50,初始感染人数为 1,屏蔽百分比为 0%,无屏蔽疾病为 100%),我们观察到在第 0 轮(第一轮指数为 0),只有 1 人被感染;而在 100 轮之后,20 人被感染,这表明 R0 是 19。换句话说,如果一个 3600 平方英尺的市场里有 50 个人,如果没有人戴口罩,仅仅 1 个人就会感染 19 个人。*

图。从 1 名感染者开始的第 1 轮(左)和第 100 轮(右)市场人员的健康状况(市场容量为 50 人)
数字 19 本身看起来并不可怕,但如果疾病的 R0 是 19,那将是灾难性的
我们以 R0 等于 2 为例,表示疾病会感染两个人。假设 2 天后,被感染的人变得具有传染性。因此,每 2 天,患者人数就会增加一倍。如果这种疾病得不到控制,66 天后,在最坏的情况下,它将感染超过 80 亿人,这比目前世界上的人口要多得多!考虑到这一点,在我们的例子(19)中 R0 是一个可怕的数字,我们想知道口罩是否能有效地降低 R0,以及减缓新冠肺炎的传播。

图。R0 = 2 的指数增长模型
市场容量和初始感染人数对新冠肺炎传播的影响
原来新感染人数和市场容量之间是线性关系:增长速度相同。相比之下,随着初始感染人数的增加,新感染人数呈对数增长:从 1 名初始感染人数开始,病毒在市场容量为 50 人时会感染 19 人,如果初始感染人数分别增加到 2 人和 3 人,新感染人数会增加到 32 人和 43 人,在初始感染人数达到 4 人后会趋于平稳。

图。受市场容量影响的新感染人数(左)和初始感染人数(右)
就新冠肺炎的传播而言,市场容量和初始感染人数的增加都加速了病毒的传播(表现为对新感染采取的步骤减少)。如果在不同的市场容量下,初始感染人数被设置为 1,则新感染的最小步数将从容量为 10 时的 12 步指数下降到容量为 100 时的 0 步。如果市场容量设置为 50,初始感染人数不同,则新感染不会晚于第 1 步。

图。感染新人所需的最少步骤。如果在 100 步之后,没有新的感染,则感染新的人所采取的步骤被设置为 110。
无论是新增感染者还是新冠肺炎的传播速度,都会随着市场容量(市场更拥挤)和初始感染者(市场初始感染者更多)的增加而增加。但是哪个因素影响更大呢?
似乎减少市场上的初始感染者比减少市场容量更能有效地减缓新冠肺炎的传播。但不幸的是,与限制市场中的人数相比,在感染者进入市场之前识别他们要困难得多,尤其是在他们没有表现出任何症状的情况下。根据斯克里普斯研究转化研究所的研究, 40%-45%的感染者是无症状的。换句话说,即使一个人感染了新冠肺炎病毒,也有近 50%的可能性这个人没有表现出任何症状,比如发烧、咳嗽或气短,但这个人能够将病毒传播给他人。
面具对新冠肺炎教传播的影响
鉴于进入市场的初始感染人数难以控制的情况,口罩会显著减少新冠肺炎的传播吗?还是勉强?
下图显示了不同情况下新感染总人数的增长与市场容量和初始感染人数的关系:1)不戴口罩,2)部分戴口罩,50%的人戴口罩,3)所有人都戴防护等级为 80%的口罩,4)所有人都戴防护等级为 95%的口罩,以及 5)所有人都戴防护等级为 99%的口罩。说 99%的防护水平,意思是如果一个人戴着口罩去了受感染的区域,这个人有 1%的概率会被感染。
在这里,我们可以清楚地看到,随着越来越多的人戴上口罩和防护等级更高的口罩,新增感染者总数趋于“扁平化”(病毒传播减少)。在市场上只有 1 名初始感染者的情况下,如果所有人都佩戴 95%防护水平的口罩,即使容量从 10 到 100 增加 10 倍,新感染人数也只会增加到 4 人。当保护水平提高到 99%时,在市场容量为 100 时,只有 1 人会被感染(最拥挤的情况)。当最初有多名感染者时,也观察到类似的情况:当 50 人中有 20 人最初被感染时,如果所有人都戴口罩,只有 4 人被新感染,而如果没有人戴口罩,则有 41 人被新感染。

图。不同场景下受市场容量(左)和初始感染人数(右)影响的感染人数对比。
此外,口罩也将大大减缓新冠肺炎的传播,即使市场上有多个最初感染者。据观察,如果没有人戴口罩,随着市场容量和初始感染人数的增加,病毒几乎立即传播。相比之下,当人们戴上口罩和防护水平更高的口罩时,病毒形成新感染所需的时间越来越长。如果市场容量和初始感染人数控制得好,病毒甚至在其生命周期中找不到下一个宿主。这强烈表明,口罩将有助于减少甚至阻止新冠肺炎的大规模传播。

图。不同情景下受市场容量(左)和初始感染人数(右)影响的感染新人所需的最少步骤的比较。如果在 100 步之后,没有新的感染,则感染新的人所采取的步骤被设置为 110。
结论
该项目旨在定量评估口罩在不同情况下如何有效减少新冠肺炎的传播:1)不戴口罩,2)部分戴口罩,3)全部戴口罩。新冠肺炎模拟器旨在模拟真实市场,数据是根据我们的假设生成的。据透露,如果所有人都戴口罩,即使在市场非常拥挤、有多个初始感染者和/或难以保持社交距离的情况下,新感染人数也可能减少到 0。虽然感染率可能被夸大了,特别是考虑到即使没有人戴口罩,人们进入受影响区域时也不应该 100%被感染。然而,这里要传达的信息是在公共场合戴口罩不仅是保护自己的责任,也是保护他人的责任。****
感谢您阅读这篇文章。这项工作是由刘泳和维多利亚苏怡平等贡献。有关新冠肺炎模拟器设计和数据分析的更多信息,请访问 my Github 。
德国新冠肺炎社会距离模拟
我们什么时候能恢复正常生活(德国情景)?

TL;博士
我使用 RKI 的基准模拟了 5 个场景(如果没有实施社交距离,到 2020 年 6 月中旬达到 1000 万活跃案例)。如果您只想查看结果,请滚动至第 5 部分。
目录
0。免责声明
1。简介
2。概述3
。数据输入
— 3.1 MIDAS 研究网
— 3.2 JHU 和 RKI 知识库
— 3.3 社会人口统计数据
4 .车型
—4.1 SIR
—4.2 SEIR
—4.3 SEIR+DH
5 .模拟
——5.1 无社交距离
——5.2 10%社交距离
——5.3 25%社交距离
——5.4 50%社交距离
——5.5 90%社交距离
6。致谢
更新 4 月 3 日从 2020 年 3 月 23 日(总理默克尔宣布国家紧急状态的那一天)开始的每个场景的预计死亡病例
0 免责声明
我不是流行病学家,所以我不能 100%保证上述情景会成为现实。我相信这种形象化将有助于解释“社会距离”的影响,通过这一点,我想强调的是,在这个疫情,每个人都扮演着重要的角色。
请记住,这是一个简单的 SEIR+DH 模型,在撰写本文时,用于训练该模型的可用数据有限。
您可以在我的 GitHub 上查看 Jupyter 笔记本中的代码
此外,我希望这将激励人们探索更多的数字和模型,而不仅仅局限于主流媒体和潜在的不那么可靠的新闻。
1 导言
这个分析的目的是对我们何时回到在德国的正常生活做出最好的“猜测”。

电晕表情符号(来源)
罗伯特·科赫研究所(RKI)对德国的“无社交距离场景”的估计在此用作本次模拟的基准。报告称,如果不采取干预措施,3 个月后(截至 2020 年 3 月 19 日),感染病例数将上升至~ 1000 万。
鉴于社会现在处于完全或完全“封锁”状态(取决于你住在哪里),我想在这次尝试中使用社会人口统计和疾病数据以及简单的流行病学模型来模拟 5 种不同的社交距离场景。
这 5 种情况如下:
- 没有社交距离
- 10%的社交距离
- 25%的社交距离
- 50%的社交距离
- 90%的社交距离
2 概述
整个项目可以很快总结在这张图表中:

项目一览
3 数据输入
3.1 MIDAS 研究网络:
我直接使用来自 MIDAS 新冠肺炎研究网络的估计参数进行分析:
- 潜伏期 —从暴露到症状和体征首次出现之间所经过的时间
- 痊愈率 —“从症状出现到痊愈的时间”,从新加坡和中国的研究期刊上获得(使用对数正态参数生存方法&在 t 时间累计痊愈/死亡人数与感染人数的比率)。
- 基础繁殖率(R0) —从一个传染者身上传染疾病的平均人数。它特别适用于以前没有感染和没有接种疫苗的人群。如果一种疾病的 R0 为 18,那么只要没有人接种过疫苗或者在他们的社区中已经对其免疫,那么患有这种疾病的人平均会将这种疾病传播给其他 18 个人。

R0 值越大表示传染病越多(来源: 健康热线 )
- 报告率 —置信区间高达 95%的最新研究表明,新冠肺炎病例的实际报告率为 75%(截至 2020 年 3 月 29 日)
为了计算每天的死亡案例,我使用以下参数:
- 临界死亡率 —如果患者不能住院,病死率约为 12%。这是来自武汉的 max 报道:估计 2019 年新型冠状病毒疾病的死亡风险,中国,2020 年 1 月至 2 月
- 从住院到死亡的时间 —该参数用于计算过去住院的人增加的死亡病例(时滞因子)。
截至 2020 年 3 月 29 日,收集的参数值如下:
Incubation period: 6.55
R0 - basic reproduction rate: 3.26
Time from hospitalization to death: 10
Recovery time: 21.02
Reporting rate: 0.75
Critical death rate - without hospitalization: 0.122
Probability of an infected case but asymptomatic: 0.179
3.2 JHU(约翰·霍普金斯大学)和 RKI(罗伯特·科赫研究所)存储库
- 确诊人数/痊愈人数/死亡人数 世界数据来源于约翰霍普金斯大学的知识库(https://github . com/CSSEGISandData/新冠肺炎/)--) 此数据只包含国家层面的数字。
*# Get total timeseries from JHU*
global_confirmed = pd.read_csv('https://github.com/CSSEGISandData/COVID-19/raw/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv')global_death = pd.read_csv('https://github.com/CSSEGISandData/COVID-19/raw/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_deaths_global.csv')global_recovered = pd.read_csv('https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_recovered_global.csv')
- RKI 每日发布的州级数字(https://NP geo-corona-NP geo-de . hub . ArcGIS . com/datasets/DD 4580 c 810204019 a 7 b 8 e B3 E0 b 329 DD 6 _ 0)
3.3 社会人口统计数据
- 年龄分布为德国 — 金字塔年龄。其他国家的数据也可以在此页面收集(某些国家截止到 2018 年)

德国的年龄金字塔—资料来源:人口金字塔
- 经合组织数据库【https://data.oecd.org/healtheqt/hospital-beds.htm提供的医院床位和医护人员数量
- 对于每个年龄组的死亡率,我使用了 2020 年 3 月 16 日“帝国理工学院新冠肺炎响应小组”报告中的数据。下表显示了每个年龄组的死亡率:

资料来源:帝国理工学院新冠肺炎应对小组
在收集了所有的社会人口统计数据后,以下是死亡率和住院率和的结果:
- 比例 _ 德 _2020 是德国人口的年龄分布

死亡率和住院率快照
4 款
4.1 先生
1927 年,Kermack 和 McKendrick 首次使用了 SIR 模型,随后该模型被应用于多种疾病,尤其是通过空气传播的儿童疾病,这些疾病在痊愈后具有终身免疫力,如麻疹、腮腺炎、风疹和百日咳。S、I、R 代表易感、感染、痊愈个体数, N = S + I + R 为总群体数。
该模型假设:
- 人口规模是固定的(即不出生、不死于疾病或死于自然原因)
- 传染原的潜伏期是瞬间的
- 完全同质的群体,没有年龄、空间或社会结构


来源: EMOD 艾滋病毒建模
其中 N(群体)= S(易感)+ I(感染)+ R(康复)
控制疾病传播的关键因素是 R0(基本繁殖率),即患病者感染的平均人数。
参数β(β)和γ(γ)定义如下:
β =人群中的平均接触率。
γ =平均传染期的倒数(1/t _ 传染)。或通常称为“回收率”
可以通过计算 R0 来获得这些参数:
R0 = β/γ
4.2 SEIR
许多疾病有一个潜伏期,在此期间,个体被感染但还没有传染性。感染的获得和感染状态之间的这种延迟可以通过增加一个潜伏/暴露群体 E,并让感染(但还没有传染性)的个体从 S 移动到 E 和从 E 移动到 I,而包含在 SIR 模型中。


来源: EMOD HIV 建模
其中 N(人群)= S(易感)+ E(暴露)+ I(感染)+ R(康复)
暴露是指人群已经暴露于疾病,但没有表现出任何症状,也没有变得具有传染性(又名——仍处于潜伏期)。因此,第三个参数δ(δ)计算如下:
δ =潜伏期的倒数(1/t _ 孵育)
4.3 SEIR + DH
- 另外两个因素 D & H 被加入到 SEIR 模型中,这两个因素分别说明了死亡病例数和住院病例数。

其中 N(人群)= S(易感)+ E(暴露)+ I(感染)+ R(康复)+ D(死亡)
这两个数字的计算方法如下:
住院病例(第 t 天)=住院率(每年龄组)*活跃感染病例(第 t 天)
为了计算死亡病例的数量,我使用从住院到死亡的时间来获得过去的住院病例(如果卫生保健系统没有超载)并估计第(t)天的总死亡病例。

死亡病例计算方法(h2d =“从住院到死亡的时间”)
- 临界死亡率 —如果没有得到适当治疗的死亡率,我使用了本报告中的值估计 2019 年新型冠状病毒疾病的死亡风险,中国,2020 年 1 月至 2 月,即 0.122
社交距离因子(s_dist) 这是一个添加到(S)和(E)变量中的参数,它们乘以 β 。由于我使用 RKI 的报告作为基准,所以对于无干预的 s_dist 的估计值为 ~ 1.2
(1) S[t] = -(s_dist * β*S[t-1]*I[t-1])/N(2) E[t] = s_dist *S[t-1]*I[t-1] — δ*E[t-1]
5 模拟
在开始场景模拟之前,我们先来看看德国的历史数据。截至 2020 年 3 月 28 日,德国已有近 60k 确诊病例 ~ 9k 痊愈,接近 500 死亡。

让我们试着预测一下未来 180 天(6 个月)会发生什么。由于本模拟中使用的死亡率是根据目前可用的研究报告的,当我们有了更准确的数字时,动态可能会改变。以下是模型的输入:
# Define parameters
t_max = 180 # forecast next 180 days
dt = 1
t = np.linspace(0, t_max, int(t_max/dt) + 1)
N = population# Current exposed cases but yet show symptoms (infectious)
E_0 = round((no_c - no_r - no_d) * RR)
# Current recovered cases
R_0 = no_r
# Current hospitalized cases (part of current infected active cases)
H_0 = func.hospitalized_case(no_c - no_d - no_r, AGE_DATA)
# Current infected cases = confirmed - recovered - deaths
I_0 = no_c - no_r - no_d
# Current deaths
D_0 = no_d
# Cummulative deaths
CD_0 = no_d# Current susceptible cases
S_0 = N - (I_0 + D_0 + R_0 + E_0)init_vals = (S_0, E_0, I_0, R_0, H_0, D_0, CD_0)# Parameters
# inverse of incubation period
delta = 1/IB
# Beta = gamma - (recovery rate = 1/infectious_day) * R0
beta = 1/RT * R0
# Recovery rate
gamma = 1/RT
5.1 没有社交距离
对于第一种没有社会联系的情况。由于 RKI 预测德国的总活跃感染病例将在未来 3 个月达到1000 万,让我们将这 1000 万作为“无社会距离”情景的基准。
这里对社会距离参数的估计是 1.2 ,这导致我们到2020 年6 月 19 日1000 万活跃感染病例

从 2020 年 3 月 23 日起没有社交距离
在这种情况下,该模型预测德国将在 7 月末左右达到其入住率峰值,在此期间至207 万活跃病例需要住院治疗,但其中只有一半得到治疗。因此,“总死亡数”曲线在这段时间后显著增加(从住院到死亡的平均时间为 10 天)。
到该预测期(6 个月)结束时,死亡总人数将达到 820 万(使用当前死亡率)

无社交距离情景—预计医院床位高峰占用率
从下面的图表来看,“没有社交距离”情景下的预计死亡案例相当高。50-59 岁年龄组的死亡病例总数最高,6 个月结束时死亡人数超过 110 万(使用当前住院率)。

2020 年 3 月 23 日无社会距离——预计死亡病例
如果没有干预,德国的医疗保健系统将从 7 月初开始超负荷运转,并在 7 月底达到高峰,预计 6 个月后总死亡人数将超过 800 万。
5.2 10%的社交距离
在这种情况下,德国从2020 年 3 月 23 日(默克尔总理演讲后)开始应用社交距离法。可以看出,与没有社交距离的情况相比,感染病例略有下降。而且预测死亡病例总数和第一个病例相差不大(~ 750 万例死亡)。

从 2020 年 3 月 23 日开始,10%的社交距离
同时,到 7 月底,德国的医疗保健能力将在同一时期超负荷运转,这一次将有 186 万病例需要住院治疗,但只有略多于 1/3 的人得到治疗。

10%的社交距离——预计医院床位高峰占用率

10%的社交距离——预计死亡案例
5.3 25%的社交距离
接下来,我们假设德国从 2020 年 3 月 23 日开始应用 25% 社交距离方法。
可以看出,与上面的其他两种情况相比,感染病例显著下降。在这种情况下,180 天后的死亡病例总数约为500 万(使用当前估计的病死率),国家医疗保健系统仍将超负荷运转(8 月中旬左右达到高峰,有 150 万病例需要住院治疗)

25%的社交距离

25%的社交距离——医院床位高峰占用率

25%的社交距离——预计死亡案例
5.4 50%的社交距离
我们已经“拉平了曲线”,但没有那么多。现在让我们看看是否每个人都遵守社交距离 50%的规则(从 2020 年 3 月 23 日起)
可以看出,与上述三种情况相比,感染病例显著下降。在这种情况下,180 天后的死亡病例总数仅为 184k ,国家医疗保健系统仍不会超负荷(9 月中旬左右为高峰)。

2020 年 3 月 23 日的 50%社交距离情景

50%的社交距离——预计医院床位高峰占用率

50%的社交距离——预计死亡案例
从 2020 年 3 月 23 日开始的 6 个月后,如果德国人遵循社交距离(90%社交距离),只有大约 4000 人死亡!
5.5 90%的社交距离
上面的场景看起来“足够好”,但如果我们真的将社交距离法则发挥到了极致呢?让我们试着模拟一下如果每个人都遵循社交距离到 90% 的情况。
正如你所看到的,如果每个人都真正遵守规则,180 天后的死亡总数将会降低到只有~4k,德国的医疗保健系统将不会超载!!

90%的社交距离

90%的社交距离——医院床位高峰占用率

90%的社交距离——预计死亡案例
6 次致谢
灵感来源于 Element AI 团队的corona-calculator(https://corona-calculator.herokuapp.com/)和 Christian Hubbs 的流行病学动态扩散模型(https://www.datahubbs.com/)
新冠肺炎测试。你的机会有多大?

阿迪·萨瓦拉在 Unsplash 上拍摄的照片
统计思想在新冠肺炎检验中的应用
注意:我不是医学专业人士,这篇博客只是我对我认为与诊断测试相关的统计学观点的看法。
检测新冠肺炎 你不需要介绍新冠肺炎,这种冠状病毒现在已经蔓延到地球上的每个国家,正在对经济、卫生系统和人们的生活造成严重破坏。
除了社会距离之外,世界各国政府的首要任务之一是对尽可能多的公民进行测试,既看谁目前携带病毒(抗原测试),也看谁已经携带病毒(抗体测试)。请注意,在这篇博文中,我将使用“阳性”来表示检测到抗体,并且此人患有新冠肺炎。
到目前为止,一切顺利。你推出测试,评估人群,然后某些人可以返回工作岗位。
评估是/否诊断测试 当你低头看测试盒(通常是一种护理点侧流设备,类似于家庭妊娠测试的工作方式)并查看结果时,问题出现了。这些测试给出“阳性”或“阴性”结果,我们经常听说这种测试是通过它们的准确性来评估的。我们总是在新闻上听到它。你做了一个准确率为 99%的测试,得到了一个阳性结果,所以很容易假设你患新冠肺炎的概率是 99%,对吗?
不完全是。
准确性是在某种评估过程中,测试正确识别的案例数,无论是正面的还是负面的。这种引用阳性/阴性测试有多好的方式的问题是,它没有区分正确的阳性和正确的阴性。
想象一下,你有一个根本不起作用的测试。无论患者、病情等如何,每次运行时它都会显示“阳性”。你在一组随机的医务人员身上进行测试,其中 98 名已知患有新冠肺炎,2 名没有。你的假测试,把每个人都诊断为阳性,最终会有 98%的准确率!
谢天谢地,有更好的方法来总结这种测试的有效性,最常见的是灵敏度和特异性。这些定义如下:

注意分母。对于灵敏度,我们有“真阳性”,当然是阳性,还有“假阴性”,,也是阳性。因此,敏感性只处理阳性病例,而逻辑与阴性病例的特异性相同。结果是灵敏度是从所有阳性病例中获得阳性结果的概率的量度,而特异性是从所有阴性病例中获得阴性结果的概率的量度。
另一种表述方式是,敏感度是得到阳性结果的概率,假设你已经患病,写为 P(+ve result|Disease)
然而,在实践中,我们感兴趣的是与此相反的,即在测试结果为阳性的情况下,患此疾病的概率,即 P(疾病|+ve 结果)。那么,在实践中,我们如何做这个翻转呢?
托马斯·贝叶斯于 1701 年出生在英国。他一生的大部分时间都专注于教会,只出版了一本关于数学的著作。在晚年,他对概率产生了兴趣,这可能是因为他想反驳大卫·休谟反对将个人证明作为奇迹证据的论点。
在他死后,一个朋友找到了关于概率的手稿并交给了皇家学会,贝氏在 1742 年被选为该学会的会员。其中一篇题为《解决机会主义中的一个问题的论文》的论文,引出了今天所知的贝叶斯定理,定义为:

注意左边的第一个词和右边的第一个词。在这里,我们可以看到我们所追求的“翻转”,即当我们知道 P(+ve result|Disease) 时,获得 P(Disease|+ve result) ,以及其他几个我们很快会谈到的术语。这个定理反过来(经过皮埃尔·西蒙·拉普拉斯的提炼)导致了今天所知的贝叶斯统计。
流行的统计类型和在许多应用中使用的统计类型被称为频率统计。这种方法基于样本中事件发生的频率来分配概率。相比之下,在贝叶斯思维中,概率与我们当前对事件的知识水平有关。后一种方法允许引入所谓的先验或预测试概率**(下面将更详细地解释),这是在收集关于事件的数据之前分配给的概率。这个预测试概率与新的证据相结合,给出一个后验概率或后验概率。****
在贝叶斯定理中, P(A) 是患过该病的概率, P(B) 是得到阳性结果的概率。这些价值观是什么?P(A)是预测试概率(如上所述),通常使用当地疾病流行率。或者,预测试概率也可以从详细的医学检查、对患者记录的回顾等中进行估计。P(B)是可以获得阳性结果的所有方式的组合,即患者可能患有该疾病并获得阳性结果,或者患者可能没有患有该疾病并获得阳性结果。具体来说,

在实践中,这样的计算通常是用一种叫做似然比的东西来完成的。这些被定义为,

其中 LR+是正似然比,LR-是负似然比。它们允许你使用一种叫做法甘诺模图的图形工具,从预测试概率到后测概率。或者,可以使用计算机快速进行计算。它们也给你一个测试有效性的指示,因为它们告诉你你的预测试概率会受到正面或负面结果的影响(见下表)。

似然比数值和后验概率的变化(来自维基百科)
精确的计算包括从概率到赔率的转换,

看看世界各地正在使用的一些新冠肺炎测试,灵敏度值似乎约为 91%,特异性约为 99%。这样我们的 LR+为 91,LR-为 0.09。相当令人印象深刻。
我们现在有了解决这个难题的所有方法,给定一个肯定的结果,对于一个给定的个体,患新冠肺炎的概率是多少。首先,让我们假设您在一个流行率为 1%的地区进行测试,并得到一个肯定的结果。考后概率是多少?

我们找到了。一个人在一次奇妙的测试中获得阳性结果后患上新冠肺炎病的概率小于 50%。
现在,想象一下如果汤姆·汉克斯怀疑新冠肺炎。不,不是真正的汤姆·汉克斯,他确实得到了新冠肺炎。我指的是查克·达拉,汤姆·汉克斯在电影《荒岛余生》中扮演的角色。如果通过一个非常复杂的事件转折,被困在荒岛上多年的查克·达拉发现了一种被冲上沙滩的新冠肺炎快速现场护理测试,并因为他有点咳嗽而决定进行它,如果它给了他一个阳性结果,这意味着什么?嗯,前测概率为零,也就是说后测概率也为零。运行测试完全是浪费时间!(当你被困在一个荒岛上时,这并不是什么大问题)。
现在让我们把它翻过来。你对医务人员进行了测试,他们在新冠肺炎的一个紧急避难所里长时间工作,却没有足够的个人防护装备。他们都有症状,但后来都康复了。他们治疗的病人都有严重的症状。他们都在艰难地呼吸。他们都发烧了。他们都与自己是确诊病例的家庭成员有过接触。现在是仲夏,普通感冒和流感的发病率很低。很难说患病率是多少,所以你用的是利用(过去)临床症状和患者病史的方法。您估计每位员工的预测试概率为 0.95。这是数字,

你已经从测试前的概率 0.95,变成了测试后的概率 1。并不特别意外。同样,这个测试可以说是浪费时间。
由此得出的结论是,考虑到你可能缺少测试,测试那些预测试概率极低或极高的人有意义吗?毕竟,在一天结束的时候,您在运行测试之后所做的事情可能不会改变。如果你非常确定某人已经感染了新冠肺炎病毒,并且计划让他们脱离隔离状态,那么用尽一项宝贵的检测结果呈阳性并不能改变什么。即使有人的预测试概率为 0.95,并且他们得到了否定的结果,这也不会显著改变事情(基于上面的 LR)。

我们得到 0.63 的后验概率。如果医生的想法是“如果他们的后验概率超过 0.5 或以上,我会允许团队成员返回工作”,这个负面结果不会改变任何事情。他们将被允许在测试前返回。之后他们也会被允许回来。
这种“治疗阈值”更容易通过图表看出。下面是一个 Python 函数,它根据给定的灵敏度和特异性值,计算出给定的预测试概率的预测试概率。
*def diagnostic_posttest(pretest,sens,spec):
lr_pos = sens / (1 - spec)
lr_neg = (1 - sens) / spec
pretest_odds = pretest / (1-pretest)
posttest_odds_pos = pretest_odds * lr_pos
posttest_odds_neg = pretest_odds * lr_neg
posttest_pos = posttest_odds_pos / (1+posttest_odds_pos)
posttest_neg = posttest_odds_neg / (1+posttest_odds_neg)
return(posttest_pos, posttest_neg)*
我们可以使用该函数以及类似于现实世界中的灵敏度和特异性值来创建预测试概率对预测试概率的图,
*import numpy as np
import matplotlib.pyplot as pltpost = list()
prev_options = np.arange(0.0, 1.0, 0.01)
for i in prev_options:
post_temp = diagnostic_posttest(i,0.91,0.99)[0]
post.append(post_temp)fig, ax = plt.subplots()
ax.plot(prev_options, post)
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.0])
plt.rcParams['font.size'] = 12
plt.title('Pretest vs Posttest Probability (sens = 0.91, spec = 0.99)')
plt.xlabel('Pretest Probability')
plt.ylabel('Posttest Probability')*
这是我们得到的阳性测试结果,

对于阴性测试结果,

正如你看到的正面结果,随着测试前概率的增加,测试后概率迅速上升。对于一个否定的结果,你需要一个非常高的预测试概率,这样预测试概率也会很高。
有多自信?所有这些还有一个方面。新冠肺炎测试通常引用的数字通常不包括置信区间。**
置信区间是围绕某个数字的值的范围,例如敏感度值,它向您显示与您的数据兼容的值的可能范围。它们是一种方法,如果你要重复你的实验,你可以在哪里找到你的结果。这样的信息是至关重要的,因为如果你将关键决策建立在一个特定的数字上,而这个数字实际上可能与现实中的不同,你可能会面临严重的问题。
我们举个例子。假设新冠肺炎测试的灵敏度和特异性分别为 88%和 90%。给定测试期间属于每个类别的案例数(真阳性、假阳性、真阴性和假阴性),我们可以计算置信区间。
假设我们这样做,最终灵敏度为 88% (85%至 92%,95%可信区间),特异性为 90% (84%至 95%,95%可信区间),其中“95%可信区间”表示其置信区间为 95%(详见这篇博文)。
本质上,这种 COVID–19可能具有低至 85%的灵敏度和低至 84%的特异性。这样我们的 LR+为 5.3,LR-为 0.18。这在实践中意味着什么?
假设你估计的预测试概率是 0.1。在这种情况下,一个阳性的测试结果会给你一个大约 0.38 的后验概率,这个概率仍然很低(见下图)。你以 0.38 的概率保持隔离吗?如果你有一份重要的工作呢?测试真的取得了什么成果吗?

同样,在前面处理一线医务人员的例子中,他们的预测试概率可能估计为 0.95。如果这个测试给你一个否定的结果,结果后测概率是 0.78(见下图)。还是很高的。

总结思路 我们已经看到,快速、即时的是/否诊断测试的结果从来都不是完美的,可以使用贝叶斯统计和预测试概率的概念将其置于有意义的环境中。阳性结果并不一定意味着这个人患有新冠肺炎,特别是如果他们在苏格兰突出部分的一个孤立的小村庄(为了这个说明的目的,请忽略人们正涌向高地自我隔离的事实)。同样,阴性结果并不一定意味着这个人没有感染新冠肺炎病毒,尤其是如果他们刚刚在前线花了 4 周时间治疗数百名感染病毒的患者。
背景很重要,在这个疯狂的测试时代,这些细节可能很重要。
如开头所述,本文只是一些统计观点的例子,并不意味着对新冠肺炎提供任何指导。
新冠肺炎:新加坡的第二次浪潮
大约在 3 月 10 日,新加坡抗击新型冠状病毒的斗争进入了一个新阶段,当时输入病例的数量开始急剧增加。这个城市国家的经历可能是仍在努力应对疫情第一阶段的其他国家煤矿中的金丝雀。

T2 从 2020 年 3 月 27 日开始实施新的社交距离规则。照片:蔡展汉
在 1 月 23 日报告首例确诊新冠肺炎病例约两个月后,新加坡已进入疫情爆发的新阶段,其特征是来自更多国家的更大一波输入性病例。
根据新加坡卫生部每日新冠肺炎公告的分类,第二波开始于 3 月 10 日左右。就像第一阶段一样,在 1 月 23 日至 09 年 3 月之间,人们担心不断增加的输入性病例将引发新冠肺炎本地传播的更大高峰。
为此,新加坡当局推出了一系列严厉的新措施,以加强社会距离,限制人群,并对来自英国和美国等新冠肺炎热点地区的“海归”进行隔离。政府已经暗示,如果有必要,它准备出台更严厉的措施。
本帖将仔细观察新冠肺炎病毒在新加坡爆发的第一波和第二波有何不同。
1。数据和警告
本文涵盖了新加坡当局在 1 月 23 日至 3 月 27 日之间宣布的 732 例确诊病例(415 例输入性病例,317 例本地病例)。图表数据来自卫生部网站的每日新冠肺炎更新。你可以在这里下载数据集,或者通过我的 Github repo 下载。

卫生部的每日更新包括宣布当天确诊的新冠肺炎病例,以及前一天检测呈阳性的病例。例如,日期为 3 月 27 日的新闻发布会将有患者在 3 月 27 日和 3 月 26 日都检测为阳性。
为了避免混淆,本文中的图表仅参考官方确认感染的日期。这些确认日期是医疗记录,与更具管理性质的公告日期相比,将更加可靠和一致。
但是,请注意,新加坡的媒体报道是基于新加坡政府每天公布的新新冠肺炎数据。如果你将那些文章中报道的数字与图表中突出显示的数字进行比较,就会发现有出入,因为它们是从不同的日期引用的。
最后,声明:这不是医学研究,我也不是流行病学家。这是为了更好地理解公开信息的潜在趋势。已经特别注意避免过度解读不完整的新冠肺炎数据。
2.3 月 10 日:一个新阶段开始了
新感染的出现与当局检测和确认它们的能力之间显然有一个时间差。但根据现有数据的分类,新加坡的新冠肺炎疫情似乎在 3 月 10 日左右进入了一个新阶段。
从那时起,输入性病例的数量开始超过本地传播的病例——起初很慢,随后急剧增加,如下图所示。

图表中的日期是指官方确认新冠肺炎感染的日期,而不是卫生部宣布的日期。
在 3 月 10 日之前,绝大多数输入性病例都是来自 mainland China 的游客或从新冠肺炎疫情发源地武汉撤离的新加坡人。
第一例与中国没有关联的输入性病例——患者 113——直到 3 月 4 日才得到确诊,几乎是在新加坡 1 月 23 日报告首例新冠肺炎病例的 6 周之后。
第 113 号患者,一名 42 岁的法国国民,曾去过法国、葡萄牙、土耳其和英国,这是一个征兆,尽管当地病例继续超过输入病例达六天之久。
3 月 10 日,输入性病例数几周来首次略微领先于本地病例(4 例输入性病例对 3 例本地病例)。一周后的 3 月 17 日,输入病例激增至 31 例。一周后的 3 月 24 日,47 例输入性病例得到确认,这是迄今为止此类病例的最高单日记录。
第二波输入性新冠肺炎病例主要来自英国和美国,这与疫情第一阶段与中国相关的输入性病例形成鲜明对比。关于输入病例变化的更详细分类可在第 4 节中找到。
在疫情的第二阶段,本地传播的病例数量也相应增加。事实上,本地传播的病例在 3 月 24 日达到了目前 31 例阳性检测的最高纪录,同一天,新输入病例的确认也达到了最高纪录。
到目前为止,当局尚未披露第二阶段的输入性和本地病例之间的任何直接联系。但是我们已经从第一阶段的几个集群中看到,这是一种明显的可能性。
3.进口-本地多米诺效应

90 号病人是 T2 第一个死于新冠肺炎的新加坡人。
输入性新冠肺炎病例如何对当地传播产生“多米诺骨牌效应”的最著名的例子发生在一对受感染的武汉夫妇身上,他们分别是 8 号和 9 号患者。他们于 1 月 19 日抵达新加坡,并在同一天拜访了巴耶利巴的生命教会和传道会。
这对中国夫妇感染了六名去教堂做礼拜的人,这些人接着又感染了另外两群人中的大约 24 人(见上图)。这两名中国公民仅在 1 月 28 日和 29 日对新冠肺炎的检测呈阳性。从 2 月 6 日起,被他们感染的新加坡人新冠肺炎病毒检测呈阳性。
鉴于该病毒的高度传染性,首次接触感染者和确认新感染之间的巨大时间差令人担忧。尽管当局现在有了更快的检测试剂盒和更多应对新冠肺炎的经验,但全面追踪接触者和护理高危人群中的患者仍是一项极具挑战性的任务。
例证:90 号病人,第一个死于新冠肺炎的新加坡人。这名 75 岁的妇女有慢性心脏病和高血压病史,于 2 月 9 日开始报告症状。但她只是在 2 月 23 日的新冠肺炎检测中呈阳性。在重症监护 26 天后,她于 3 月 21 日去世。
距离疫苗问世还有几个月,甚至几年的时间,对新冠肺炎的多米诺骨牌效应最明显的应对措施就是人们减少社会交往,以最大限度地减少任何潜在的传播链。对于没有出过远门的新加坡人来说,这意味着要认真对待社交距离,避开人群。对于最近刚从海外回来的人来说,这意味着要严格遵守的自我检疫令。
新加坡在这一新阶段控制新感染的能力,或者说是最近广为人知的“拉平曲线”的能力,将在很大程度上取决于这里的居民遵守这些新规则的程度。
4。新加坡输入性新冠肺炎病例的变化概况
在撰写本文时,新加坡的 415 例输入性新冠肺炎病例有旅行史,涉及 45 个不同的目的地。然而,卫生部在这方面发布的信息并不一致,一些输入病例的旅行史被公布为“东盟”、“欧洲”和“东欧”,但没有详细说明。卫生部还将 19 例输入病例的旅行记录标记为“待定”,但没有解释为什么没有这些信息。
如果我们排除这四个有问题的类别,输入性新冠肺炎病例前往(或来自)的 41 个国家是:英国、美国、印度尼西亚、中国、菲律宾、马来西亚、法国、泰国、西班牙、意大利、斯洛文尼亚、摩纳哥、台湾、爱尔兰、土耳其、阿联酋、加拿大、澳大利亚、波斯尼亚、挪威、日本、俄罗斯、冰岛、塞尔维亚、匈牙利、丹麦、瑞士、巴基斯坦、印度、荷兰、斯里兰卡、奥地利、比利时、克罗地亚、墨西哥、捷克共和国、葡萄牙、荷兰、南非、德国和瑞典。
至少有 60 例输入病例曾传播到上述两个或更多国家。在新加坡,绝大多数输入性新冠肺炎病例都有一个单一的来源,目前以英国为首:

这个图表不包括卫生部记录中的模糊类别,如“欧洲”、“东欧”、“东盟”和“待定”。
如果我们包括抵达新加坡前有多个旅行目的地的输入病例,那么与英国有关联的病例数将达到 155 例。对于这些病例,卫生部的新闻稿没有详细说明患者可能是在哪里感染的。
当我们根据迄今为止我们所看到的疫情的两个阶段来划分输入性病例时,输入性病例的地理分布更加惊人:第一波从 1 月 23 日到 3 月 9 日,第二波从 3 月 10 日起:


左图:2009 年 1 月 23 日至 3 月的输入病例。右图:3 月 10 日至 3 月 27 日输入病例。
中国在第一阶段的输入病例中占主导地位,在第二波中自然没有出现在图表中,因为新加坡当局在 1 月下旬针对中国游客和最近有过大陆旅行史的人实施了严格的旅行限制。
来自英国和美国的输入性病例激增,似乎主要是由于新加坡人(尤其是学生)因东道国对新冠肺炎疫情处理不当而回国。
对有英国旅行史的 155 例输入病例的分类显示:
- 113 人(73%)是新加坡人,14 人是新加坡永久居民。
- 大约一半,即 78 岁,年龄在 18 到 25 岁之间。
当局预计更多在英国和美国的新加坡学生和居民将在未来几周内回国,他们对此不抱任何希望。根据从疫情第一阶段吸取的教训,新加坡已经要求从这两个国家返回的居民直接从机场前往酒店,接受为期两周的隔离。
5.越来越多的本地集群
检查本地案例最有趣的方式是通过网络图来查看集群是如何连接的。考虑到绘制集群所涉及的工作量,我将把这个问题放在另一篇文章中。
这里有一个我通过riche 的优秀调查模板得到的快速版本。你可以在这里访问它。

这些集群中有几个仍在增长,所以这里的数字没有反映最新的计数。这张图表的数据取自新加坡卫生部 1 月 23 日至 3 月 27 日的新闻稿。
迄今为止最大的本地聚集性病例是 SAFRA 句容聚集性病例,涉及 47 例确诊病例,这些病例以各种方式与 2 月 15 日的一次晚宴活动有关。许多参加活动的人有共同的社交圈,并参加了可能加剧病毒传播的联合活动。
下面的图表有助于更好地了解本地传播中的峰值是如何跟踪这些集群的出现的:

从 3 月 24 日起本地病例的激增是由于大约同时出现了至少三个新的集群:
- PCF 凤山丛(26 例及以上);第一例出现在 3 月 23 日。
- 多佛法院国际学校集群(至少 8 起案件);第一例出现在 3 月 24 日
- 新加坡邮政中心集群(至少 5 个案例);第一例出现在 3 月 24 日
在新聚集的第一个病例和随后所有本地病例的高峰之间通常有几天的间隔。按照全球标准,新加坡的接触者追踪制度已经相当激进。
但这里的目标是进一步减少建立新确诊病例近期活动史所需的时间,以便可以快速检测他或她的密切接触者,并将其与其社交圈子中的其他人隔离开来。我将在以后的文章中更详细地介绍本地集群。
6.比较第一波和第二波新冠肺炎病例的关键人口统计学指标
疫情仍在快速发展,因此在这一点上制作太多详细的图表没有多大意义。我再次在 fluore 上加载了一个单独的调查模板,供那些想要详细探索第一波和第二波人口统计数据的人使用。你可以在这里找到。
我将只关注几个引起我注意的关键领域。
6.1 本地输入病例组合的变化
我们已经从之前的图表中看到,在第二波期间,新加坡的输入性病例数量出现了急剧上升。如果把所有的数字放在一起,那就更令人吃惊了:
**Phase Category Total Confirmed Cases**
First Wave Local 131
Imported 32Second Wave Imported 383
Local 186

互动图表可用此处。
从 3 月 10 日起,外来病例增加了 10 倍多。
6.2 性别混合
我们继续看到新冠肺炎病毒检测呈阳性的男性多于女性。
**Phase Gender** **Total Confirmed Cases**
First Wave M 92
F 71Second Wave M 328
F 241
6.3 年龄范围的变化
在第二波中有一个明显的年轻新冠肺炎患者高峰,在 20-29 岁年龄组的 179 个病例中可以看到。这可能是因为从英国和美国回国的学生人数很多。
**Phase Age Range** **Total Confirmed Cases**
First Wave Ages 50-59 38
Ages 30-39 35
Ages 60-69 29
Ages 40-49 28
Ages 20-29 17
Ages 70-79 10
Ages 0-9 4
Ages 10-19 2Second Wave Ages 20-29 179
Ages 30-39 101
Ages 50-59 86
Ages 40-49 82
Ages 60-69 64
Ages 10-19 23
Ages 70-79 22
Ages 0-9 6
Ages 80-89 6
我的笔记本里有这篇文章更详细的分析。在这一点上,我会避免走得太远。
结论
第一波和第二波新冠肺炎疫情之间的显著差异凸显了在全球化时代试图遏制疫情的复杂性。
在第一阶段,新加坡反应迅速,相对较快地控制了疫情,而疫情在很大程度上仍以中国为中心。
鉴于疫情现已席卷全球几乎所有角落,第二阶段将更难管理。其他国家政府如何应对本国的新冠肺炎病例,将对新加坡产生直接影响,正如我们从从英国和美国回国的难民人数激增中所看到的那样。
在可预见的未来,新加坡将不得不密切关注新输入病例的多种潜在来源,同时努力控制本地传播。
遏制疫情还将带来日益复杂的国内政策挑战。在疫情爆发的第一阶段,即 1 月 23 日至 09 年 3 月,输入性病例中只有 8 名新加坡人。
在第二阶段,从 3 月 10 日起,新加坡人至少占了 239 例输入性病例,在这一类别中占了绝大多数:
**Phase Category Nationality Total Confirmed Cases**
First Wave Imported China 17
**Singapore 8**
Indonesia 2
Singapore PR 2
France 1
Italy 1
UK 1Second Wave Imported **Singapore 239**
Singapore PR 34
UK 16
Indonesia 15
Australia 10
Malaysia 9
Philippines 9
毫无疑问,在第二波输入病例中,新加坡人的激增与归国学生或没有多少选择的担忧家庭有关,但这个数字暗示了新加坡当局在说服本国公民不要出国旅行以避免疾病卷土重来方面面临的更大挑战。
这个信息可能会持续一段时间,但新加坡或其他国家在这方面的吊桥能抵挡第三次甚至第四次新冠肺炎疫情爆发多久呢?三个月?六个月?一年?
现在还不知道。
本帖图表的笔记本和数据在我的 Github 回购里。如果你发现了错误或者对这个来自新加坡的小数据集做了一些有趣的事情,请告诉我。在以下时间 Ping 我:
推特:蔡振鸿
领英:www.linkedin.com/in/chuachinhon
我关于新加坡新冠肺炎疫情的其他帖子:
* 新冠肺炎:新加坡首批 100 名完全康复患者的视觉记录
* 恐慌性购买的背后:一个神秘的“泄露”和随着 S'pore 提高其病毒警戒级别 FB 的激增
* 病毒式传播:随着武汉冠状病毒疫情恶化,新加坡的食品安全反应如何激增
编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
分析新冠肺炎趋势的开源代码——第一部分
GitHub 和 Google 联合实验室使用约翰·霍普斯金大学的数据库跟踪新型冠状病毒传播的用例
我开发了一个 python 代码库,并将其发布在我的 GitHub 库中,使用由约翰·霍普斯金大学维护的数据库来呈现新型冠状病毒的传播。在本文中,我不提供任何预测模型,而是专注于以有意义的方式提供数据,旨在对新型冠状病毒感染如何在不同地理区域传播做出循证判断。尽管有明显的迹象表明官方数据被严重低估,但这个代码库旨在使新冠肺炎趋势的官方数据和分析工具包民主化。
使用约翰霍普金大学的数据库分析 2019 年新冠状病毒病例的代码库…
github.com](https://github.com/sidbannet/COVID-19_analysis)
这些数据在各个国家报告的新冠肺炎病例的地理散点图和时间序列图中呈现,以比较各个地理区域的传播率。此外,还特别关注美国的利差率。以坚持只回答“数据怎么说?”我的分析仅限于报告的病例。约翰·霍普斯金大学报告的新冠肺炎病例有三种类型,分别是 1) 确诊感染,2) 报告死亡,3) 报告康复。
新冠肺炎教在世界各地传播的地理散点动画。

地理散布图例
气泡的颜色代表3 天内感染人数增加的百分比,作为传播率的衡量标准。

动画展示新冠肺炎确诊病例数。气泡的大小与确诊病例的数量成比例,气泡的颜色显示传播速度

动画展示新冠肺炎确诊病例数。气泡的大小与新冠肺炎的死亡人数成比例,气泡的颜色显示了传播速度
冠状病毒像任何传染病一样,最初以指数增长速度在给定人群中传播。这意味着每日新增感染病例与特定人群中的感染人数成正比。衡量新冠肺炎病毒传播速度的一个很好的指标是感染人数增加的天数。在本节中,受冠状病毒影响的人数使用时间序列图纵坐标中的对数标度表示。在横坐标图中,显示了前 500 例报告病例的天数。当病毒找不到新的感染者时,通常会达到饱和点,然后时间序列纵坐标会在对数范围内变平。
最上面的三个子图显示了每个国家的确诊病例(左)(中)和(右)的数据。底部的三个子图显示了美国各州的相同指标。这些图中仅显示了截至 2020 年 4 月 3 日确诊病例超过 10000 例的国家(韩国除外)和至少有 5000 例确诊病例的美国各州。**

自社区爆发开始至 2020 年 4 月 3 日的新冠肺炎趋势

从 500 例到 1 万例确诊病例的天数
并非所有国家都遵循上述对数图中的相同轨迹。影响这些轨迹的因素是 a)检测的可用性,b)人口密度和 c)采取的政策措施。
****澳洲、比利时和荷兰用了 16 到 18 天报告了 1 万例病例,而美国、中国、意大利、德国和西班牙用了 9 到 12 天的时间达到 1 万例确诊病例。美国和土耳其显示在第 11 天左右报告的病例突然增加。这可能是由于冠状病毒检测活动的增加。加拿大和比利时的病例还在不断出现。根据这些图,法国、英国、意大利和德国将在大约 30-35 天内报告 10 万个病例。意大利的确诊病例轨迹已经显示出大约 40 天持平的充分证据。西班牙目前的传播率高于意大利,但也显示出传播率放缓的一些初步迹象。美国正走在一条不同于任何其他国家的轨道上,而且几乎没有迹象显示曲线变平。
到目前为止,德国、T42、瑞士、加拿大、澳大利亚在限制新冠肺炎死亡人数增长率方面做得非常好。另一方面,美国没有显示新冠肺炎死亡曲线减缓的证据。

从最初的 500 例增加到 5000 例的天数
在美国范围内,各州的传播率差异很大。纽约和新泽西和的传播率最高,而华盛顿和的传播率则截然不同。纽约用了 7 天时间报告了第一万个病例,而华盛顿从全州第一个 500 个病例的类似增长可能需要 25 天以上。在其他州中,加利福尼亚州、佐治亚州和得克萨斯州可以归为一类,它们在大约 16-18 天内报告了 1 万例病例。****
如何使用开源代码库来重新分析数据
求知欲强的观众可以使用 谷歌 平台重新分析和绘制本文中的人物,代码也发表在 GitHub gist 上。
使用谷歌合作实验室的新笔记本,人们可以克隆代码库和。
- 克隆代码和数据仓库
- 设置环境
***# Clone repository*
!git clone https://github.com/sidbannet/COVID-19_analysis.git
%cd ./COVID-19_analysis
!git submodule init
!git submodule update --remote**
加载分析和绘图所需的包。
- 分析工具
- 绘图工具
***# Import necessary modules*
**from** **tools** **import** collection **as** cll
**import** **plotly.tools** **as** **tls**
**from** **plotly.offline** **import** iplot
**import** **plotly.express** **as** **px****
解析数据库中的数据
- 设置包含数据和解析数据的方法的类
- 解析数据
***# Setup data class and parse the database*
d = cll.DataClass()
d.parse()**
制作时间序列图
绘制每个国家和每个美国州的新冠肺炎时间序列数据
- 确诊病例数
- COVID 的死亡人数
- 从 COVID 中恢复的数量
以对数标度绘制这些变量,以突出自首次爆发以来疫情相对于天数的指数增长。
***# Make some meaningful timeseries plots*
fig, ax = d.plots_timeseries(
n_outbreak=500, n_filter_country=10000, n_filter_state=5000) fig.set_size_inches(w=24, h=12)
_ = [axes.set_ylim([10, 50000]) **for** axes **in** ax[:, 1].flat]
_ = ax[0, 0].set_xlim([0, 40])
_ = ax[0, 0].get_legend().remove()
_ = ax[0, 1].get_legend().remove()
_ = ax[1, 0].get_legend().remove()
_ = ax[1, 1].get_legend().remove()**
地理分散动画,以可视化新冠肺炎的趋势
在下面这张geoscatter动画图像中,气泡的大小代表了报道的新冠肺炎病例数。气泡的颜色代表病例数的每日增长率。动画帧表示从 2020 年 1 月 22 日开始的日期。
***# Data frame customized for plotly express geo-scatter*
df_global = d.df_global.copy()
date_time = [str(date) **for** date **in** df_global.date]
date_str = [str.split(date, ' ')[0] **for** date **in** date_time]
df_global['Date'] = date_str*# Geo scatter of confirmed cases*
fig = px.scatter_geo(df_global, locations="iso_alpha", color="rate",
color_continuous_scale='jet', range_color=[1.0, 2.0],
hover_name="country", size="confirmed",
animation_frame="Date",
title='Confirmed case',
size_max=int(80),
width=2000, height=1000,
projection="natural earth")
fig.show()*# Geo scatter of deaths*
fig = px.scatter_geo(df_global, locations="iso_alpha", color="rate",
color_continuous_scale='jet', range_color=[1.0, 2.0],
hover_name="country", size="death",
animation_frame="Date",
title='Deaths',
size_max=int(80),
width=2000, height=1000,
projection="natural earth")
fig.show()**
— —直到下次
新冠肺炎疫苗和治疗时间表

第 3、4 期新冠肺炎干预临床试验时间表。数据来自 ClinicalTrials.gov。
可视化所有新冠肺炎介入临床研究的完整时间表。
什么时候事情会最终恢复正常?我们都见过许多模拟“拉平曲线”的模型和新冠肺炎的投影。现在让我们来看一个预示新冠肺炎末日的模型。在这篇文章中,我们将介绍新冠肺炎目前的干预措施,包括治疗和疫苗。我们将在一个全面的时间表中很好地将这些放在一起。最后,我们将简要探讨目前临床试验中的治疗方法的相似之处。
从美国国立卫生研究院(NIH)的临床试验网站上,我们可以看到数百个正在进行的与治疗新冠肺炎相关的临床试验。我们想特别关注介入性临床试验。介入性研究包括疫苗、药物和疗法。从这些干预性研究中,我们希望将重点放在最近的研究上,并将有一个合理的最终完成日期,所以让我们专注于 2019 年至 2025 年之间的研究。
从 NIH 临床试验网站上,我们正在寻找的相关数据包括研究的标题、干预的类型、干预的组成部分以及干预的预计完成日期。首先,让我们看看什么类型的干预措施目前正在试验中!这第一个饼图显示了不同类型的新冠肺炎干预,从药物到生物制剂到诊断(等等)。
临床试验中新冠肺炎的干预类别。符合该类别的病历报告数量显示在饼图中。“其他”被列为 ClinicalTrials.gov 的一个类别。数据来自 ClinicalTrials.gov。
很明显,大多数临床试验是针对药物和生物制剂的。很好!这意味着有许多临床试验在寻找疫苗或治疗方法。
现在的问题是在这些干预措施中使用了什么成分。我们能否发现一个统一的趋势,并对哪些药物可能成功对抗新冠肺炎做出推论?
要回答这个问题,每个临床试验都必须列出方案中描述的干预措施的组成部分。使用一系列自动请求来获取相关的组件信息。这些成分然后被浓缩和匹配,并且在下面,我们使用一个饼图来显示在至少 3 次试验中包含的成分。
临床试验中新冠肺炎治疗的干预成分。符合该类别的病历报告数量显示在饼图中。数据来自 ClinicalTrials.gov。
似乎目前大多数治疗都着眼于羟氯喹和洛匹那韦-利托那韦。专利药物,如 Gilead 的 Remdesivir,出现的次数不多,因此没有在可视化中列出。值得一提的是,这种可视化包括仅仅评估这些药物安全性的研究(不仅仅局限于 3、4 期)。尽管如此,在作品中看到不同类型的治疗还是很有趣的。
酷!羟氯喹和其他药物的疗效将在许多临床试验中进行严格评估。现在我们会问,这些药物多快能上市?
要回答这个问题,每个临床试验必须包含其研究开始日期、主要完成日期和研究完成日期。研究开始日期是指研究正式开始的日期。主要完成是指研究人员估计他们可以做出主要结果结论的日期(即这种治疗安全吗?这种治疗有效吗?)而研究完成日期是指研究人员估计他们可以做出主要、次要和不利结论的日期(即这种治疗有效吗?这种治疗会造成长期的不良影响吗?).临床试验有 4 个阶段,后期阶段(3,4)测试干预的临床效果。下面,我们将主要关注 3 期和 4 期临床试验。
3-4 期干预的临床试验时间表
第 3、4 期新冠肺炎干预临床试验时间表。将鼠标悬停在各点上,查看相应的研究。数据来自 ClinicalTrials.gov。
该图中绘制的信息与顶部第一个图中绘制的数据相同。它是专门针对 3 期和 4 期临床试验的,因为它们是部署准备最充分的。这一总体数字(不受阶段限制)也在下面的补充部分以互动形式呈现。
从 2020 年 2 月 1 日开始到 2020 年 4 月 18 日结束的鲑鱼色阴影框代表了第一次广泛注意到新冠肺炎和这一可视化的(当前)日期。3 个气泡(有时 2 个)代表研究开始日期、主要完成日期(如果包括)和研究完成日期。大多数研究都是在这个范围内开始的。
在这个跟踪器中,我们可以专门跟踪临床试验的阶段,以及跟踪它们的预计结束日期。我们可以在下面的柱状图中看到这些最终研究完成日期的分布。

新冠肺炎干预研究完成日期柱状图。数据来自 ClinicalTrials.gov。
该直方图显示了与新冠肺炎相关的所有介入性临床试验的预计最终研究完成日期。似乎大多数审判将在 2020 年末和 2021 年初结束。很有可能,我们可以期待一种安全有效的疫苗在 2021 年的某个时候向公众提供。
结论
在我们拥有安全、方便、有效的疫苗和治疗方法之前,我们应该期待社会距离仍然是常态。根据相关 3 期和 4 期临床试验的完成日期,这可能会在 2021 年初的某个时候发生。特别是因为我们都试图在这个时候拉平曲线,在疫苗出来之前过早地开放这个国家将对公共卫生产生重大影响。请记住这一点:目前还没有治愈或预防新冠肺炎的方法。尽管临床试验管道中的新干预措施看起来很有希望,例如 Moderna 的新型 mRNA 方法和 Gilead 的 Remdesivir,但这些公司都不会在今年晚些时候结束临床研究。现在,我们比以往任何时候都更需要维护强有力的社区标准,照顾那些受病毒影响最严重的人,并记住这一切都会过去的。正是在这些不确定的时期,我们作为一个社区的纽带受到了考验,我们将比以前更加强大。
在此之前,我们将继续关注这些治疗的进展!
补充材料和方法

生物制品干预临床试验时间表。数据来自 ClinicalTrials.gov。
互动版第 3、4 期干预措施:【https://plotly.com/~nathan2wong/28/#/
【所有干预的互动版:https://plotly.com/~nathan2wong/7/#/
仅生物制品互动版(更多疫苗):https://plotly.com/~nathan2wong/5/
方法:
- API 请求获取所有临床试验数据的 XML,使用嵌套循环获取具体的试验信息,包括干预和完成日期。
- 将响应格式化为 JSON,用 BeautifulSoup、Regex、Datetime 和其他过程解析响应。
- 熊猫保存不同临床试验的记录。
- 可视化与 Matplotlib,Seaborn,Plotly。
接下来的步骤
- 对世卫组织临床试验数据库执行相同的可视化。
- 每天刷新以获取更新
- 跟踪单个临床研究的进展
可根据要求提供代码。请将所有信件寄至:berkeley.edu 的 nathanwong。
编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
最后更新:2020 年 4 月 18 日。
新冠肺炎:我们对非药物干预了解多少?

来源:Giang (GiGi) Nguyen。详细分析可以在我的 Github Repo 或者 Kaggle 笔记本上找到
上面的预测是由 SEIR 模型产生的,该模型估计,鉴于干预,新冠肺炎感染从 4 月 10 日开始下降,并可能在美国超过 100 万确诊病例时达到峰值。该模型将在本文稍后详细讨论。
免责声明 :本分析的目标是提供有关新冠肺炎传播的数据信息。建议基于我的数据探索和个人观点。因此,预测仅作为参考,不应作为未来事件的最终验证。 关于新冠肺炎的任何健康相关问题都应咨询您的医生和医疗保健提供者。
通过早期的《接触者追踪、广泛检测和隔离法》,韩国在实施后 1 个月内就将传播率控制在了医疗保健能力之下。该病例与中国有相似的模式,中国在早期通过全面封锁武汉抑制了疫情的增长,当时每天约有 100 多例确诊的新病例。

来源:Giang (GiGi) Nguyen。详细分析可以在我的 Github Repo 或者 Kaggle 笔记本上找到
尽管一些国家的形势已经稳定,但其他国家的形势仍在上升。在缺乏新型冠状病毒疫苗的情况下,我们正试图利用其他非药物因素来抑制病毒的传播,并将其保持在医疗保健能力之下。
在这篇文章中,我将评估 3 个主要话题:
- 关于传播、潜伏期和环境稳定性,我们知道些什么?例:各地区气温、湿度、风速数据。
- 我们对新冠肺炎风险因素了解多少?例如:一个国家吸烟人口的百分比或病人的重症监护室床位数。
- 我们对非药物干预了解多少?隔离、取消大型集会、大范围检测、追踪接触者等。
背景
为了加入抗击新冠肺炎的行列,我参加了由 Kaggle 发起的为期 4 周的新冠肺炎预测挑战。
虽然挑战包括预测确诊病例和死亡人数,但主要目标不仅仅是做出准确的预测。在这个项目中,我的首要任务是确定似乎影响新冠肺炎病毒传播率的关键因素,这些因素最终可以作为参考,帮助医疗和政府机构做好准备,并随着疫情的发展做出调整。
数据
约翰·霍普金斯大学系统科学与工程中心(JHU·CSSE)提供并每天更新 Kaggle 竞赛数据。train 数据包含 1 月 21 日至 4 月 17 日全球 184 个国家的新冠肺炎确诊病例和死亡病例的累计数。出于预测目的,可从 4 月 2 日至 5 月 14 日获取测试数据。
除了原始数据集,我还利用了来自不同 Kagglers 贡献的多个开源数据,包括但不限于天气、人口统计、干预和关于疫情的测试数据集。
分析

来源:Giang (GiGi) Nguyen。详细分析可以在我的 Github 回购或者 Kaggle 笔记本上找到
目前,全球约有 250 万感染病例,其中 32%主要在美国
天气
下面是一个互动图表。随意点击“播放”或拖动时间线栏,查看感染病例的数量如何随着湿度水平的变化而变化。
来源:Giang (GiGi) Nguyen。详细分析可以在我的 Github Repo 或者 Kaggle 笔记本上找到
注 :颜色代表湿度水平,圆圈大小显示新冠肺炎病例数。
天气有不同的组成部分:温度(华氏)、风速、降水、气压、湿度和日照时间(每个地区太阳照射地球表面的持续时间)。应用多元线性回归模型,我想了解哪些变量与病毒的传播率显著相关。
我的初步发现表明,温度、风速和湿度与全球感染病例数显著相关。特别是,当湿度增加时,确诊病例的数量会减少,而温度和风速则显示出相反的结果。
然而,效果因地区而异。以西班牙为例:虽然湿度似乎没有显著影响(p > 0.05),但较高的温度与新冠肺炎病例的下降密切相关。当风速与感染病例的减少显著相关时,美国也是一个特例。
虽然我们了解天气因素与病毒传播之间的相关性,但这些变量在相隔几英里的情况下可能非常多样。因此,调查其他潜在因素至关重要。
人口统计和风险因素

来源:Giang (GiGi) Nguyen。详细分析可以在我的 Github Repo 或者 Kaggle 笔记本上找到
韩国和德国是每千人 ICU 床位数最高的两个国家之一。因此,与确诊病例数量相当的同行相比,他们的死亡率最低(2-3%)。
在分析之前,我假设有足够数量的 ICU(重症监护病房)床位,我们可以挽救更多情况危急的新冠肺炎患者。结果证实了我的假设。
当我们增加 ICU 病床数量时,死亡人数在统计学上显著下降。
为了检验人口统计学和风险因素与冠状病毒致死病例之间的相关性,我再次应用了多线性回归模型。当我们增加 ICU 病床数量时,死亡人数有统计学意义上的显著下降 (p < 0.05)。相反,一个国家的中位年龄越高,致命风险的趋势越高。该模型反映了现实生活中的情况,因为意大利是中位年龄最高的国家之一(~45 岁),并且该国迄今为止冠状病毒死亡率最高(~13%)。
而吸烟或有潜在健康问题(肺癌等)的人口数量。)未显示死亡率的统计显著结果,应进行进一步的科学调查。
广泛的检测显示对抑制新冠肺炎的传播有显著的积极影响。
此外,广泛的检测显示对抑制新冠肺炎的传播有显著的积极影响,因为检测次数的激增与传播次数密切相关。如果我们能够扩大家庭检测试剂盒的规模,让更多的家庭可以使用,更多的人可以在家里立即进行分类,降低传染的风险,并最终成为更准确的接触者追踪的基础。证明这一点的最佳案例是韩国,该国在第一天就引入了广泛的测试。
城市人口密度也被发现显著影响新冠肺炎传播。城市越拥挤,确诊病例越多。这确实反映了美国人口众多的州(纽约、马萨诸塞州、加利福尼亚州等)的情况。)报告的冠状病毒病例最多。
虽然我们理解足够数量的 ICU 病床、呼吸机和个人防护设备的积极影响将挽救更多新冠肺炎患者的生命,但我们迫切需要评估非药物干预在抑制传播率方面的潜在作用。
非药物干预
如果我们仔细观察中国和韩国在一段时间内的感染病例,它们实际上遵循逻辑曲线。尽管传输速率呈指数增长,但是,在某个被称为拐点(传播的中点)的点上,传输速率会减慢。

来源: 3Blue1Brown 通过 Youtube
在这篇文章中,我不会详细讨论逻辑曲线背后的数学原理,但基本上,我会计算疫情的增长因子,以深入了解哪些国家可能已经到达拐点。增长因子可以通过第 N 天的病例数变化与 (N-1) 天的病例数变化之比来计算。例如,如果一个国家的增长因子稳定在 1.00 左右,那么这可能是该国已经到达拐点的迹象。
这让我们想到了流行病学中的房室模型之一——SEIR 模型,代表易感+暴露+传染性+康复:

来源:维基百科 SEIR 模型
对于 2003 年爆发的 SARS,患者只需 2-7 天就能出现症状。这就是我们能够更快采取行动抑制疾病传播的原因。然而,这种新型冠状病毒需要长达 14 天的时间才能出现明显的症状——这是一颗定时炸弹,后果要严重得多。
在 SEIR 模型中,这段时间被称为潜伏期。基本上,它是指个体已经被感染,但他们自己还没有传染性的这段时间。这发生在隔间 E (对于暴露)。
以下是该模型的细分:

来源:流行病计算器作者 Gabriel Goh
在求解模型之前,我将假设有一些干预会导致再生数(R0)减少(,如更多的 ICU 床位、呼吸机或隔离、广泛检测、接触者追踪、疫苗等。)。
出于分析的目的,干预期被设置为 60 天,预测期是从训练日(4 月 17 日)起提前 300 天进行预测。注意,这些时间点是我的假设;因此,它们不是固定的,而是可以被灵活地修改以检查不同的场景。
在求解上述微分方程后,我们将对每个国家拟合 SEIR 模型,以预测感染率,在那里感染率将达到拐点和平台。(特别感谢 潘善品 为本代码奠定基础)
让我们先来看看美国受影响最大的州——纽约州:

来源:Giang (GiGi) Nguyen。详细分析可以在我的 Github 回购或者 Kaggle 笔记本上找到

来源:Giang (GiGi) Nguyen。详细分析可以在我的 Github Repo 或者 Kaggle 笔记本上找到
好消息!我的模型预测,美国已经在 4 月 10 日左右达到拐点,并将很快持平。

来源:Giang (GiGi) Nguyen。详细分析可以在我的 Github Repo 或者 Kaggle 笔记本上找到
西班牙的模式与此类似,预计将在 4 月 19 日达到反射点,并在变得更加稳定之前达到最多约 50 万+感染病例。

来源:Giang (GiGi) Nguyen。详细分析可以在我的 Github Repo 或者 Kaggle 笔记本上找到
然而,意大利预计要到 7 月 14 日才会达到拐点,这距离现在还有 3 个月。这可能是因为它们的生长因子每天都呈指数增长。
除了 SEIR 模型,我还尝试了随机森林和贝叶斯岭模型对天气和人口数据进行预测。然而,首要目标同样不仅仅是准确的预报,而是确定新冠肺炎传播的关键指标,这些指标最终可以作为抑制疫情的参考。
结束语
在#AtHome 自我隔离期间学习新东西(流行病学的分室模型、疫情的指标等)是一次非常有益的经历。),在与我以前所做的完全不同的领域进行分析,并(潜在地)提供一些有意义的见解,以帮助我们共同抗击疫情。
总之,我希望你保持安全和健康,洗手,戴口罩和#StayHome 来帮助我们在前线的医疗英雄!

来源: Siouxsie Wiles 通过分拆
链接到我的 Github Repo
白宫科技政策办公室(OSTP)召集了一个联合研究小组和…
github.com](https://github.com/giginghn/covid19-non-pharmaceutical/blob/master/README.md)
进一步阅读
新冠肺炎-我们对越南的情况了解多少?
深入研究越战新冠肺炎患者数据
编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
根据约翰霍普金斯大学的数据,目前全球已有超过 340 万例新冠肺炎确诊病例,至少 239622 人死亡,分布在 212 个国家和地区(2020 年 5 月 2 日更新)。

图一。新冠肺炎确诊病例在各个国家和地区的分布。资料来源:Tran Nguyen。详细分析可以在我的 Kaggle 笔记本或者我的 Github 上找到。
确诊病例和死亡人数呈指数上升,在许多国家达到了严峻的里程碑。与此同时,越南目前总共只有270 例新冠肺炎确诊病例,无死亡病例。现在,越南已经连续 16 天没有本地传播的新病例,连续 8 天没有新病例。这给我们留下了许多问题要问。
越南发生了什么?
- 越南官员报告的新冠肺炎病例数是否被低估了?测试在越南进行得好吗?
- 越南政府是否隐瞒了当地新冠肺炎疫情的范围?如果不是,那么在如此“真实”的低病例数和无死亡的情况下,越南是如何控制病毒的?
- 我们对越战新冠肺炎患者了解多少?这些病人有什么特征可以帮助降低越南的感染率吗?
作为一名具有分子生物学和生物信息学背景的数据分析师,我过去也在 PCR/qPCR(用于新冠肺炎的标准检测方法)方面做了很多工作(实验),自从世卫组织宣布 2019 年 12 月武汉爆发一小批未知肺炎以来,我就对新冠肺炎感兴趣。当疫情沿着自己的路线跨越国界时,我对许多主题的兴趣越来越大:测试(测试,以及更多的测试)、早期测试和接触者追踪、流行病监测、新型冠状病毒基因组、患者症状、疫苗开发等。我住在湾区(美国加利福尼亚州),经常在清晨阅读/观看世界各地的冠状病毒实时更新/简报,因此我非常熟悉新冠肺炎的情况和许多国家为控制疫情而采取的措施。越南的低病例数给我们大家提出了许多问题。因此,我决定收集数据,并利用互联网上所有可用的信息进行独立研究。
具有讽刺意味的是,越南医疗保健系统的一个重要特点是隐私法不像美国、加拿大或欧洲那样严格。因此,越南的新冠肺炎患者数据是公开的。在某些情况下,他们的地址、姓名、个人联系方式、日常活动和习惯(例如,在市场上的哪个商店买东西)都是细节。
在本文的其余部分,我将向您展示越南新冠肺炎患者数据集,并逐步回答上面的一些问题。(测试和接触者追踪——隔离值得拥有自己的注释,即将推出)。
**免责声明 **
- 这是我的个人作品,与任何机构都没有关系。虽然这个分析是数据驱动的,但我的评论反映了我的个人观点。
- 我的结果基于从越南卫生部网站和越南主流媒体收集的数据。这些数据可能有偏差,反映的是互联网上公开的信息。然而,对于那些对越南新冠肺炎疫情感兴趣的人来说,它可以作为一个很好的参考。(老实说,到目前为止,我对任何有关越战新冠肺炎·疫情的报道的范围都不满意,所以我决定自己做一个)。
数据
- 越南数据通过网络删节获得,人工整理自越南卫生部网站和越南其他主流媒体。
- 世界数据从由约翰·霍普金斯大学系统科学与工程中心(JHU·CSSE)运营的2019 新型冠状病毒视觉仪表板的数据仓库中获得。
- 越南新冠肺炎患者数据集,以及我在 Kaggle 笔记本上的完整报告(新冠肺炎:越南数据和新冠肺炎:世界数据)都可以从这些网站获得并下载。
我们学到了什么?
1。新冠肺炎疫情在越南的增长速度比大多数国家都慢,到目前为止还没有死亡病例。

图二。新冠肺炎确诊病例在一些国家的增长速度有多快 (Y 轴是对数刻度,但为了便于解释,标签保持为实数(100-100 万例))。与其他国家相比,越南的新冠肺炎确诊病例数量一直较低。来源:Tran Nguyen。详细分析可以在我的 Kaggle 笔记本上找到。
越南与中国接壤,于 2020 年 1 月 23 日报告了首例新冠肺炎确诊病例,与韩国(1 月 20 日)、美国(1 月 21 日)、英国(1 月 31 日)几乎同时。从那时起,每个国家都有自己的控制疫情的具体策略。大多数国家现在已经从遏制范式(早期追踪、隔离传染源)转向严重缓解范式(减少传播的策略)。虽然失去了一些 F0 病例,但越南仍然安全地保持在遏制阶段。
随着活跃病例(目前住院的新冠肺炎患者)数量显著减少,曲线变得平缓(图 3)。请注意,在越南,所有的新冠肺炎患者,包括无症状的病例,都住院了。相比之下,在美国,无症状病例或症状轻微的人被建议呆在家里,除非接受医疗护理。

图 3。越南新冠肺炎确诊病例的增长速度有多快。活跃病例包括无症状患者和“再感染”病例。
在整个疫情期间,每日病例数一直保持在个位数的低水平,在高峰期,每日病例数低于 20 例(见图 4 中的每日病例图)。

图四。越南新冠肺炎疫情可以用两个不同的波来描述:第一波(2020 年 1 月 23 日至 2 月 16 日)和第二波(2020 年 3 月 6 日至 4 月下旬)。在每日的新新冠肺炎病例中,输入性病例的数量仍然占主导地位。
有趣的是,新冠肺炎输入和本地传播病例的增长率有相同的趋势,这两者加起来就是总确诊病例。此外,输入病例的数量仍然大于本地传播病例。这一趋势表明,随着时间的推移,越南一直能够控制疫情:本地病例从未超过输入病例。
2.越南从欧洲和美国获得的新冠肺炎输入病例多于从中国获得的病例
注意:疾病无国界,这种新型冠状病毒也是如此。因此,这种分析是模棱两可的,只能作为参考意见。
越南的新冠肺炎疫情可以用两种不同的波浪来描述。(越南新冠肺炎疫情的全貌,包括确诊病例、时间表、患者概况、传染源、主要感染群等。可在本笔记中找到。
- 第一波来自中国的输入病例最多。唯一从美国输入的病例(如图所示)来自患者 BN7。该患者可能是来自中国的传播病例,因为该病例报告得非常早(2020 年 2 月 2 日),并且该患者在从美国到越南的途中确实在中国武汉中转了 2 小时。
- 第二次浪潮始于许多来自欧洲(主要来自英国)的病例。
这一趋势与美国的情况非常一致(美国从欧洲获得的新冠肺炎病例多于从中国获得的病例

图 5。越南新冠肺炎输入病例的传染源。*此分析的注意事项:国家列表可能被低估,因为一些患者可能在回到越南之前去过许多国家,但没有报告。他们也在不同的地方过境,可能在这些短暂的过境期间被感染。(例如,患者 BN7 可能是在中国武汉转机 2 小时时被感染的)。在这项分析中,包括过境国在内的所有国家都包括在内。
有想过吗?
请记住,这份报告可能会有偏见,原因如下:为了对传染源有一个概括的看法,在这项分析中,包括“过境”国家在内的所有国家都包括在内。许多国家可能在传染源列表中占据主导地位,因为它们是主要的国际旅行枢纽 患者中转地,如英国、俄罗斯、阿联酋等
在这份传染源名单中(图 5),英国主要与 54 例确诊病例有关(占输入病例的 27%),几乎是第二大传染源法国的 3 倍,与 19 例病例有关。这一事实背后的原因不仅仅是因为英国是繁忙的国际旅游中心之一。但是,它表明,自疫情爆发初期以来,英国新冠肺炎病例的实际数量可能要高得多。英国因其对冠状病毒的反应而受到批评。当时没有采取适当而迅速的措施:没有隔离,没有旅行禁令,……请注意,越南的大多数外国新冠肺炎患者来自英国(图 6)。

图 6。越南国籍的新冠肺炎患者
为什么越南从欧洲和美国获得的新冠肺炎病例比从中国获得的多?中国是一个与越南接壤的邻国,与越南有着密切的日常贸易关系。 对我们来说是个谜。其他变量,如当地天气(温度、湿度)、种族背景和基因变异、疫苗接种情况、文化和社会行为,特别是人们的意识(武汉震中是当时越南社交媒体和新闻上的热门趋势),可能有助于减缓来自中国的病毒传播。
3.越南新冠肺炎患者的年龄和性别分布大多与特定人群有关,而不是随机的,这表明疫情在很大程度上得到了控制。

***图 7。越南新冠肺炎患者的年龄、性别、国籍和旅行史分布的小提琴图。关于小提琴图的说明:它是一个盒子图和一个核密度图的混合体。白点:中间值;中间粗灰条:四分位数范围;小提琴图的 Wider 和 skinner 部分:人口中的成员接受给定值的概率分别较高和较低。
为导入案例:
- 大多数越南新冠肺炎输入病例年龄在 20-30 岁之间。他们是去国外学习和培训的学生和年轻员工。更多详情,请参见越南新冠肺炎患者数据集中的样本行。
- 大多数外国患者都是老年人,男性为 50-70 岁,女性为 45-60 岁。他们很可能是退休旅行者。
为本地案例:
年龄趋势似乎与越南特定的感染人群有关:年轻时的外国人与佛酒吧烧烤(一家餐馆和酒吧)人群有关;大多数越南女性患者与巴赫迈医院等的食品供应公司有联系。
= >目前,在这个小数据集的情况下,无法判断是否有任何年龄性别的人群感染新冠肺炎病毒的风险更高。当所有病例似乎都与特定的聚集性和旅行团体有关时,越南的疫情似乎在很大程度上得到了控制。
4.接近 65%的越南新冠肺炎患者在确诊为病毒阳性时无症状:
如果越南没有早期检测和检疫,情况可能会更糟。

****图 8。270 名越南新冠肺炎患者病毒检测呈阳性时的症状。值得注意的是,大约 65%的病例是无症状(显示无症状)。注意,为了更谨慎起见,这里的无症状病例称为推定(原因可在本报告末尾找到)。来源:Tran Nguyen。详细分析可以在我的 Kaggle 笔记本或者我的 Github 上找到。
在所有 270 例越南新冠肺炎确诊病例中,只有 35.2%的患者在病毒检测呈阳性之前或之后出现症状。值得注意的是,只有 6.3%的病例报告了****(气短/胸闷/轻度肺炎/呼吸衰竭)。大多数有症状的患者报告了轻微的感冒/流感样症状(如发烧、咳嗽、喉咙痛、疲劳等)。) (占全部病例的 25.4%)。****
在有症状的患者中,常见的症状包括发烧、咳嗽和喉咙痛。

图九。报告了有症状患者的详细症状。在总共 270 例病例中,只有 35.2%的病例有症状。来源:Tran Nguyen。详细分析可以在我的 Kaggle 笔记本上找到。
从这个结果我们可以推断出什么?
如果越南没有迅速作出反应,进行检测并早期隔离人员,这些新冠肺炎病例中的 90%以上将继续经常出现在公共场所,不知不觉地在社区中传播病毒。
如果越南对考试采取和其他国家一样的政策,比如美国(我目前生活在美国,最了解这种情况),会发生什么?一场灾难:超过 90%的患者没有资格接受新冠肺炎测试。在这些患者身上检测到任何严重的新冠肺炎相关症状之前;在它们变得“足够”有资格进行测试之前;当他们徘徊在等待测试结果的时候,病毒可能已经悄悄地传播了。自第一波感染(2020 年 1 月 23 日)以来,应该会有许多“热点”。当来自欧洲的第二波感染如火如荼时(从 2020 年 3 月 6 日第 17 号患者开始),情况将会异常严重。(此处查看越南两次感染浪潮的更多详情)。
5.越南新冠肺炎患者(确诊后)的住院时间约为 2 周,主要是因为越南严格的出院政策。

图 10。越南新冠肺炎患者的平均住院时间。请注意,在越南,所有新冠肺炎患者,包括无症状病例,均已住院。因此,大多数越南新冠肺炎患者病情较轻。只有少数患者出现了更严重的并发症。
越南新冠肺炎患者(大多数症状轻微)的平均住院时间约为 2 周。在一个罕见的案例中,患者 BN51 在正式出院前已经接受了 13 次检测(参见越战新冠肺炎患者数据集的参考和注释)。
与越南患者相比,外国人住院时间更长。原因可能是因为医院内的环境(食物、医疗保健中的语言障碍)、种族背景和基因变异,和/或他们的年龄组:大多数外国人是退休的旅行者,他们更容易受到病毒的影响。
越南卫生部网站上的新冠肺炎病例出院标准如下:
“新冠肺炎患者在 48 小时内连续两次实验室检查呈阴性,至少连续 3 天没有发烧,生命体征正常,血液检查正常,胸部 x 光检查有所改善,可以出院。出院的病人必须(在家里/旅馆)再隔离 14 天。”
讨论大纲视图:
1 例住院时间仅 1 天。原因可能是:
- 住院时间从患者被正式确认为新冠肺炎阳性之日算起,而不是从患者住院、出现症状和/或采集样本进行检测之日算起。因此,该患者在被确认为病毒阳性之前可能已经住院。
- 公布检测结果的时间可能因患者而异,取决于他们从当地实验室和国家卫生和流行病学研究所实验室进行了多少次检测/确诊检测。
讨论新冠肺炎测试的详细说明即将发布。
6.越南有 270 例新冠肺炎确诊病例,目前没有死亡病例。
一些住院时间长(超过 30 天)的患者表示,他们的病情更加严重。不同来源的重症患者数据并不一致(每个患者出现严重症状的时间、患者 id 等)。)所以在分析中省略了。然而,你仍然可以看一看越南新冠肺炎数据集。这是对它的一种理解:
在重症监护室(ICU)收治的少数新冠肺炎患者中,一些人被插管并康复;2 -3 例接受了 ECMO 治疗(体外膜肺氧合)和强化透析。但是到目前为止,没有死亡。重症新冠肺炎患者出现好转迹象;感谢医护人员和医院的巨大努力。早期反应(病例识别、隔离、接触者追踪、隔离)有助于避免卫生保健系统的负担,从而降低发病率和死亡率。
“一个很好的经验法则是,一旦你所在的城市或城镇出现确诊的新冠肺炎死亡病例,病毒可能已经在你所在的社区存在了两周左右。”
这条规则可能不是一个真实的事实,但是当还没有确认新冠肺炎死亡的时候,想到越南仍然是“安全的”,这是非常令人鼓舞的。
越南官员一直在努力遏制病毒?请继续关注,我的媒体页面将很快提供这方面的可视化。
带回家的信息
凭借如此小的样本量(270 例新冠肺炎确诊病例)和公开的患者数据集、,我们可以更好地了解新冠肺炎患者的概况。
曲线已经变平;越南被誉为“疫情中一个异常成功的故事】;越南政府已经开始解除一些隔离措施和封锁。然而,整个国家需要保持警惕,保持耐心,并“准备在需要时采取措施”。否则,在冠状病毒疫苗和/或针对新冠肺炎的特效疗法问世之前,越南可能会失去已经取得的进展。
我同题其他笔记:
**关于无症状/有症状病例的注意事项
关于健康状况数据的注意事项 :我没有任何知情人,也没有医院的文件。患者的健康状况收集自越南卫生部网站和越南主流媒体,有 2 个显著的局限性:
(I)每个患者描述的症状依赖于患者及其密切接触者的记忆,而这些记忆可能是模糊的。
㈡健康记录不是从医院文件中正式收集的,因此这些记录可能被少报。
然而,我得到的数据仍然是一个很好的参考来源,原因如下:
(I)主流媒体似乎“渴求”信息,因此,他们报道了任何可能的信息。例如,患者 BN204 被报告没有症状,但留在同一隔离室的另一人回忆说,该患者确实打喷嚏。而这个微不足道的症状被举报了。所以主流媒体不太可能漏掉任何案例。
㈡许多病例没有提及患者的健康状况(我将这些病例报告为“未报告”)。其他人被报告说他们的“健康状况稳定”(被报告为“未报告(稳定状况)”,我们可以假设他们没有表现出任何症状。
(iii)当汇总“未报告”、“未报告(病情稳定)”和“阳性时无症状”的病例时,我们得到 64.8%,接近于越南卫生部网站上公布的 63.33%的无症状确诊病例。详细分析可以在我的 Kaggle 笔记本或者我的 Github 上找到。
新冠肺炎将增加保险业对人工智能的采用
保险公司将转向人工智能,以削减成本、降低风险并产生客户洞察力

迈克·泰森(Mike Tyson)有一句名言:“每个人都有一个计划,直到他们被打中嘴巴”。每个公司都有一个到 2020 年的战略计划。然后,新冠肺炎走进了拳击台。
保险业受到新冠肺炎和经济困难的沉重打击。随着许多保险公司专注于现金保护,如果领先的保险公司在人工智能方面进行明智的投资,它们可以从危机中变得更加强大。保险公司的大规模客户数据集及其著名的手动流程创造了一些“快速取胜”的人工智能机会。
保险公司必须主动采用人工智能,因为商业前景并不乐观。伦敦劳埃德保险社估计【2020 年承保损失将达到 1070 亿美元。保险公司正在寻找数十亿美元的业务中断和贸易信用保险损失索赔(当买方不能支付卖方时的保险)。
保险单的销售将受到经济活动下降的影响。货物和商品的生产和流动停滞不前。这意味着需要货物、能源、商品、航运等保险的公司越来越少。
许多保险公司将从冠状病毒时代中摆脱出来。根据国际货币基金组织的说法,他们将直接步入自大萧条以来最严重的衰退,这将减少对某些个人和商业保险的需求
为什么是现在的 AI?
乍一看,大流行后的经济似乎不是投资人工智能的最佳时机。毕竟,企业不应该尽可能多地保存资本吗?
事实上,这是开发人工智能能力的大好时机。人工智能擅长自动化逻辑、重复的过程,并从数据中产生洞察力。这使得保险公司能够削减成本并发现新的收入来源。AI 软件厂商的成熟意味着 AI 工具不需要从零开始构建。如果保险公司了解他们的业务需求,并制定人工智能战略来满足这些需求,在人工智能方面的小额投资可以实现高投资回报率。
大型保险公司多年来一直在投资数字化转型。将数据转换为数字格式,拥抱移动和基于网络的客户互动,以及升级技术栈,这些都给了这些公司快速采用人工智能的基础设施。数字化转型为 AI 转型埋下了伏笔。
保险业务优先级
在大流行后的经济中,保险公司应该关注三个优先事项:降低成本、降低风险和客户洞察。
新冠肺炎和经济衰退将在短期内影响保险公司的收入(承保收入)和费用(索赔)栏。在市场回暖之前,保险公司的当务之急是降低成本和风险。
为了降低成本,保险公司应优先考虑流程和索赔自动化。他们将简化工作流程,以便用更少的人完成同样的工作。人工智能工具,如智能机器人流程自动化(RPA) 将与此相关。
为了降低风险,保险公司将投资于更好的欺诈检测工具,因为在经济困难时期,欺诈行为预计会增加。根据英国保险协会(ABI)的数据,2008 年的经济衰退导致欺诈性保险索赔比 2007 年增加了 17%。
保险公司也将通过提高承保标准来降低风险。这意味着更好地理解风险,并投保更高质量的风险,以防止大型意外索赔。机器学习和自然语言处理(NLP) 工具可以搜索过去的保险单,并了解如何为新保单定价。
然后,保险公司可以专注于保持收入流和发现新的收入来源。投资人工智能获得客户洞察将产生巨大的投资回报,因为保险公司拥有大量客户数据。由机器视觉支持的企业搜索软件可以快速搜索内部数据库和文档库,为代理和客户服务人员提供 360 度的客户视图。
降低成本的人工智能:通过智能 RPA 实现理赔自动化
保险公司可以使用智能 RPA 来自动处理索赔,从而降低成本并更快地支付索赔。索赔处理充满了智能 RPA 可以解决的挑战,例如手动数据输入、多数据源(文档、电子邮件、图像、移动应用程序)和时间密集型决策。
传统的RPA 软件在不使用人工智能的情况下自动执行手动和重复性任务。例如,它只是记录和复制员工的动作和鼠标点击,以生成发票或报告。这只有在流程从不改变的情况下才有效。例如,当发票布局或报告要求发生变化时,大多数传统 RPA 工具都必须更新。
来自 UiPath 和 Automation Anywhere 等厂商的智能 RPA 系统为 RPA 工具添加了机器学习、NLP 和机器视觉。智能 RPA 不只是复制人类操作,而是在处理新数据和不断变化的需求时,找到最有效的方法来自动化任务。
AI 增强的 RPA 可以在索赔生命周期的三个阶段减少时间和成本:数据输入、验证和裁决。
在数据输入和验证阶段,RPA 机器人自动从多个来源手动输入数据。机器视觉和机器学习可能会使机器人适应不断变化的模板、文档格式和验证规则。机器学习还允许机器人在获得新数据或有人指出错误时进行学习和改进。
裁决阶段决定是否应该支付或拒绝索赔。机器学习和 NLP 允许机器人分析过去的索赔决定,并通读保险单文件,以确定如何处理当前的索赔。
智能 RPA 功能强大,因为它可以自动执行需要多人跨团队完成的任务。如果部署得当,它可以解放理赔人员,让他们将精力集中在高价值和复杂的理赔上。
降低风险的人工智能:改进核保和欺诈检测
承销
人工智能增强的承保提供了三个好处:通过数据洞察更好地管理风险,自动化任务以更好地利用承保人的时间,以及通过撰写更高质量的业务来提高竞争优势。
大多数保险公司只处理 10-15%的数据。
核保传统上依赖于经验、规则和判断。承销商考虑过去的政策、风险表、客户档案、索赔历史、行业/市场风险,并评估新政策如何影响投资组合的整体风险。
在大流行后的经济中,提高承保标准至关重要。在这种环境下,保险公司承担不起误判风险和招致巨额损失的后果。面临的挑战是,保险商不得不评估大量的保险单,这使他们捉襟见肘。
根据埃森哲的一项研究,大多数保险公司只处理了他们拥有的数据的 10-15%。有太多的数据源——过去的保单、远程信息处理(汽车保险)、可穿戴设备(健康保险)、第三方数据库(例如航运数据)和社交媒体。人类无法大规模处理这些信息。即使是自动核保工具也只能起到这么大的作用,因为它们不够“智能”,无法处理简单案件之外的任何事情。
人工智能可以帮助保险商更快、更准确地评估政策风险。机器学习和 NLP 工具可以“阅读”和理解过去的保险单,并帮助保险商为新风险构建稳健的保单。预测分析工具可以研究类似保单的过去索赔、损失和其他风险指标,以预测未来损失的可能性和大小。
人工智能工具还可以帮助保险商随着时间的推移监控风险,这在保险单续签时非常有用。人工智能初创公司 Cape Analytics 利用地理空间图像从上方拍摄房地产。机器视觉然后跟踪属性如何随时间变化。保险商可以在更新这些财产的保险单时使用这些见解。
人工智能不会取代人类保险商。人工智能工具只是提供更高质量的数据洞察。承销商有责任利用这些见解建立一个有利可图的商业账簿。人工智能驱动的分析也让保险商得以专注于复杂和高价值的业务。
欺诈检测
美国联邦调查局估计美国非健康保险欺诈每年超过 400 亿美元,这可能使家庭每年额外花费 400-700 美元。
机器学习可以分析历史索赔和客户历史,以检测潜在的欺诈行为。机器视觉和图像识别可以研究汽车或房屋潜在损坏的图片和视频,并标记可疑案件。
阿里巴巴集团旗下的金融科技公司蚂蚁金服打造了一款名为丁孙保的汽车保险移动应用。该应用由机器视觉提供支持,使用手机的摄像头来检测汽车的损坏,并立即支付索赔。理论上,该应用程序还可以标记汽车被故意损坏的可疑索赔。
欺诈检测本质上是模式识别,即识别与过去的欺诈案例相匹配的特征。机器学习是这方面的理想选择。在过去欺诈的大型数据集上训练的模型可以比人类更快地发现新索赔中的可疑模式。此外,随着更多真实世界的数据输入,模型变得更好。
面向客户洞察的人工智能:企业搜索软件
保险公司比大多数其他行业拥有更多的客户数据。如果你是个人客户,保险公司知道你的人生阶段、家庭、医疗和旅行史、房屋和汽车所有权等等。如果你是企业客户,他们对你的业务和员工非常了解。他们也知道你的保险历史。
在一个完美的世界里,保险公司将利用这些数据对任何客户进行 360 度全方位的观察。客户服务将是天衣无缝的。向上销售和交叉销售机会很容易被发现。
实际上,客户数据以不同的格式存储在互不相连的系统中(例如文档、电子邮件、图像、pdf)。数据集通常太大,无法及时搜索,而且还受到访问权限的限制。
人工智能支持的企业搜索 软件使员工能够搜索公司的数字系统,包括文档数据库、CRM 系统、电子邮件、网站、文档、呼叫中心日志等。工作人员可以使用问题或关键字进行搜索,并调出回答该问题的相关媒体。
企业搜索系统使用机器视觉来识别屏幕上的图像和文本。光学字符识别(OCR)用于将扫描的 pdf 中的文本数字化为 word 文档或电子表格。NLP 用于解释文本。
远程工作的兴起使得企业搜索系统更加引人注目。员工可以搜索信息,而不用花时间寻找同事。
调查索赔的索赔理算员可以搜索类似的索赔(例如,过去 2 年中的 2016 款银色丰田卡罗拉)。他们还可以调出证明文件和过去的欺诈案例。
承销商可以搜索过去的客户和保单,为新保单定价。销售人员可以获取客户的信息,以确定他们最可能需要的产品和服务。
客户服务代理可以在通话过程中访问客户信息,并增加客户查询的响应时间。在经济低迷时期,当公司争夺不断缩水的客户资金时,良好的客户服务是留住客户的关键。
在大流行后的经济中,360 度客户视角是一个强大的竞争优势,因为它有助于公司留住好客户并吸引新客户。更重要的是,这些客户洞察使保险公司能够创造和营销正确的产品组合,这将推动他们在经济复苏时实现增长和更大的市场份额。
保险高管的外卖
新冠肺炎事件后,保险公司的第一反应将是削减成本和降低风险。虽然一些高管会收紧钱包,但其他人有机会进行小规模的战略性人工智能投资,这些投资有可能快速获得投资回报。更重要的是,当经济好转时,人工智能的采用现在可以让主动的保险公司领先一步。
在这个充满挑战的时代,保险高管和商业领袖应该如何对待人工智能?他们应该如何选择 AI 项目?他们应该内部构建 AI 工具还是从供应商那里购买?
答案会根据公司的独特情况而有所不同。一般来说,公司应该在短期内着眼于低成本和高投资回报率的项目。高管还必须深刻理解他们的业务需求、痛点和 AI 用例。然后,他们应该选择满足这些需求的人工智能工具。一些公司走出去购买人工智能产品,并试图在以后找出他们的业务需求——这通常不会有好结果。
内部构建人工智能工具或购买供应商软件都有其利弊。虽然内部构建需要时间、工程师和数据科学家,但该产品是根据您的需求量身定制的。从供应商那里购买更快更便宜,但是产品可能与您的流程和数据不完全兼容。
保险公司与供应商合作开发定制工具的混合方法是另一种方法。这加快了实施速度,同时确保了良好的产品适应性。
最后,实施人工智能项目需要技术和业务团队共同努力。商业领袖和功能专家对于确保人工智能解决方案适合当前的业务需求并能够根据不断变化的需求进行定制至关重要。
编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
有天赋的新冠肺炎
使用 BERT 模拟冠状病毒讨论

一些背景
除非你一直生活在一块足够幸运的岩石下,不在新冠肺炎广袤的疆域之内,否则你会意识到这种病毒正在席卷全球。在撰写本文时,约 25 万病例已被确认,死亡人数超过 1 万人。不鼓励群众集会,商店和餐馆关门,国家关闭边境,在家工作是强制性的,而不是特权。这是件大事。
它几乎占据了媒体的所有讨论,优先于 2020 年美国总统大选或英国最终在不到 9 个月的时间里永远离开欧盟等话题。人们在社交媒体上充斥着 COVID 信息,这只能意味着一件事:数据。等待分析的新数据。我们会分析它。
为什么
为什么要分析文本数据?这里想象的商业案例是什么?
在社交媒体时代,每个人都可以在一个平台上发表自己的观点,从客户那里获得直接和即时的反馈从未如此容易。因为人们在网上发表他们的意见,组织不仅有天赋,也有义务利用这一点,并从客户群发布的意见中提取可操作的见解。
然而,社交媒体数据是巨大的。非常辽阔。一个中等规模的组织将很难记录、理解、总结和展示他们的客户在网上发布的所有观点、抱怨和赞扬;即使他们雇佣了整个团队来做这件事。当他们可以使用数据科学时,他们为什么要这么做。
什么
我们将尝试在冠状病毒讨论的快照中揭示潜在的主题。为了更好地理解我们将如何实现这一点,让我带你踏上主题建模的历史之旅。请把你的掌声留到最后。
经典作品
想象一下。现在是 2003 年。克里斯蒂亚诺罗纳尔多刚刚为曼联首次亮相,迈克刚刚在《老友记》中向菲比求婚。三位计算机科学家建议在主题建模领域使用一种之前在遗传学领域首创的算法。问题中的算法是潜在的狄利克雷分配,被称为 LDA,因为没有人能发出第二个单词。该方法使用概率方法来基于单词共现将文档分配到主题中。这是一个压倒性的成功,这个模型被羽翼未丰的 NLP 社区广泛采用。
经典的主题建模方法,如 LDA T1 或 T2 LSA T3 已经存在了一段时间。这些是建立在文本数据的文档术语矩阵表示上的,可以以相对较低的成本非常有效地工作。然而,它们确实缺乏捕捉关于我们文本中单词的位置或顺序的任何信息的能力,也缺乏捕捉它们彼此之间有多相似的能力。
让我们得到向量
你眨眨眼——现在已经是 2013 年了,但你还在看电视。在《了不起的盖茨比》中,利奥·迪卡普里奥第一次苦笑着举起了酒杯,麦莉·赛勒斯像一个灾难球一样出现了。布鲁诺·马斯在那里。与此同时,托马斯·米科洛夫(Tomas Mikolov)正在尝试使用浅层神经网络来改进谷歌搜索引擎,并发现他能够将单词映射到 N 维向量空间,该空间可以捕捉单词在数字位置上相对于彼此的意义。一个灯泡突然出现在他的头上,他发布了 word2vec 模型,并随之向世界释放了 word2word 命名法的瘟疫(参见 doc2vec,node2vec,seq2seq,graph2vec…)。
worder 嵌入方法是数字文本表示中的一个主要步骤。这一系列技术将语料库中的单词映射到向量空间,最常用的是使用神经网络(例如 word2vec 或 GloVe)。单词嵌入给上述概率模型带来的一个主要好处是,在训练数据中给定上下文的情况下,它们能够将单词之间的相似性表示为向量空间中的接近度;比如猫和小猫会比猫和木工彼此距离近很多。这种方法已经被广泛使用了很多年,但仍然有局限性,因为它只能将单词映射到一个单一的向量,无法捕捉同一单词在不同上下文中的不同含义。
变压器组装
画面又变得模糊了。当你的视线清晰时,你注意到手机上的日期是 2018 年 10 月 11 日。科罗娜对你来说只不过是一个啤酒品牌。谷歌仍在不知疲倦地努力保持他们作为搜索引擎的地位,这一次是雅各布·德夫林来拯救他们了。他发表了一篇关于使用转换器-编码器深度学习算法进行文本预测任务的论文。他将其命名为“变形金刚的双向编码器表示”,幸运的是,它被缩写为伯特。效果很好。非常好。 没有人确定为什么 。
BERT 不仅在许多下游 NLP 任务中击败了单词嵌入方法,而且对我们来说更重要的是,它可以在不同的上下文中为同一单词指定不同的向量表示。这对于同音异义词来说尤其重要:例如,当我给某人我的地址并且如果我称呼某人时,单词称呼具有完全不同的含义。
这个网站以前已经多次介绍过 BERT,但是如果你还没有遇到过它,我建议你绕道去阅读它。Jay Alammar 的博客提供了一个很好的总结,他致力于用芝麻街的角色来说明模型是令人敬畏的。一定要回来,因为接下来会很有趣。
我们现在已经看到了文本表示已经走了多远(它已经走得更远了),所以让我们来测试一下。
我们将使用发布在冠状病毒爆发主题上的推文样本。然后,我们将使用 BERT 在向量空间中表示它们,使用它们的单词嵌入值的平均值。然后,我们可以假设,如果在向量空间中相似意思的单词彼此更接近,我们可以将附近的 Tweets 分组在一起,以找到共同话题的集群。我们的高级工作流程是:
- 收集数据:搜索关于冠状病毒的微博
- 预处理数据:执行通常的文本清理步骤
- 嵌入文档:使用 BERT 找到每条推文的向量表示
- 降维:使用主成分分析来降低向量的大小,同时保持方差
- 聚类嵌入:应用聚类算法来查找具有相同含义的推文组
- 评估主题:试着理解主题的内容
所有这些都是为了回答这个问题:人们在 Twitter 上谈论的与冠状病毒有关的话题是什么?
怎么做
在这一节中,我将介绍我的方法,并分享我的一些代码。如果你只对目的地感兴趣,而不是旅程,你可以跳过这一部分。
数据收集和清理
我使用 Twitter 搜索 API 在 3 月 11 日找到了包含“COVID”或“冠状病毒”字样的推文,这让我在全球范围内获得了 17998 条英语推文。
让我们来看一个例子:
@RepKinzinger 我知道你有很多无能需要“克服”,而且你在冠状病毒监测中一直保持着“难以置信的警惕”。但是你愿意解释一下你的政党与你在莫斯科的“朋友”达成了什么样的协议和默许吗?https://t.co/a5dx9skaa5
我们通过一系列预处理步骤运行数据;由于这个话题在其他地方已经讨论过很多次了,我就不再赘述了。我把所有东西都改成小写,去掉超链接、提及、非字母数字字符和换行符,去掉停用词,剩下的用字母表示。上面的文本现在看起来像这样:
“知道很多无能克服令人难以置信的警惕冠状病毒监测会蒂基火炬特朗普主义者关心解释协议默许党结交朋友莫斯科”
文档嵌入
我们将使用 Flair Python 库,这是一个由 Zalando Research 在 PyTorch 上开发的框架,使用预先训练的单词嵌入模型的组合来嵌入我们的推文。
注意:我用 Google Colab 来嵌入推文,大约需要 30 分钟。您的里程可能会有所不同,但如果像我一样,您没有特别强大的机器,我会建议您使用免费的 GPU 访问。
我们将初始化单词嵌入模型:
import torch
!pip install flair # install Flair on Google Colab
from flair.embeddings import FlairEmbeddings, DocumentPoolEmbeddings, Sentence, BertEmbeddings# initialise embedding classes
flair_embedding_forward = FlairEmbeddings(‘news-forward’)
flair_embedding_backward = FlairEmbeddings(‘news-backward’)
bert_embedding = BertEmbeddings(‘bert-base-uncased’)# combine word embedding models
document_embeddings = DocumentPoolEmbeddings([bert_embedding, flair_embedding_backward, flair_embedding_forward])
这将给我们每个 Tweet 一个大小为(1,7168)的张量,所以我们将初始化一个大小为(17998,7168)的空张量,并用我们的文档向量迭代填充它:
# set up empty tensor
X = torch.empty(size=(len(df.index), 7168)).cuda()# fill tensor with embeddingsi=0
for text in tqdm(df['text_cl']):
sentence = Sentence(text)
document_embeddings.embed(sentence)
embedding = sentence.get_embedding()
X[i] = embedding
i += 1
这需要一些时间,所以去喝一杯吧。或许洗一次碗。
我们现在有一个(17998,7168)维的张量,其中填充了每个 Tweet 的嵌入。至此,我们已经完成了 PyTorch,因此我们将从 GPU 中分离张量,并将其转换为 NumPy 数组:
X = X.cpu().detach().numpy()
del(X)
torch.cuda.empty_cache()
主成分分析和聚类
我们希望将这些向量聚类到主题中,我们将从 scikit-learn 调用凝聚聚类来实现这一点。自底向上的层次聚类算法的记忆复杂度为 O(n ) ,所以我们将使用主成分分析来加速这个过程。毕竟我们刚刚看完一个进度条 30 分钟。
顺便说一句,我确实测试了许多聚类算法(K-means、BIRCH、DBSCAN、具有完全/平均相似性的 Agglomerative ),但 Ward 似乎在大多数情况下表现最好。我将此归因于它识别较小边缘簇的能力,并且似乎不会不顾一切地将我的数据点分成相等大小的组,因此它有利于挑选出不一定与主要讨论对应的潜在主题。
让我们将向量的维数减少到长度 768——我选择这个数字有些随意,但是 BERT 本身会产生这个大小的向量,所以它对我们来说应该足够好了,同时还将数据大小减少了大约 80%。
from sklearn.decomposition import PCApca = PCA(n_components=768)
X_red = pca.fit_transform(X)
我们将用 10 个聚类初始化算法,拟合我们的数据,并将聚类标签分配给我们的主数据框架:
from sklearn.cluster import AgglomerativeClusteringN_CLUSTERS = 10# WARD CLUSTER
ward = AgglomerativeClustering(n_clusters=N_CLUSTERS,
affinity='euclidean',
linkage='ward')pred_ward = ward.fit_predict(X_red)df['topic'] = pred_ward
这会产生以下主题分布:

按主题分类的推文分布
我们可以看到我们选择的聚类算法的好处。主要的话题,比如 0 和 3 被挑选出来,但是我们设法把一些边缘的讨论分开,比如 5 和 8。
我们可以在二维空间中可视化主题群:

以二维形式表示的主题群
热门术语
我们现在已经给每条推文分配了一个主题,但是我们如何理解它们呢?我们将找到每个主题中 TF-IDF 得分最高的单词和短语(单词和双词);也就是说,我们将识别在一个主题中出现很多但在其他主题中不出现很多的术语。为此,我们将在自定义函数中使用 scikit-learn 的TfidfVectorizer()。因为我们要处理几个大文档(将每个主题视为自己的文档),所以我们将文档频率限制为 50%,确保提取的术语不会出现在总数的一半以上。这一步有助于排除非常常见的词(如冠状病毒),这对识别主题没有太大帮助。
from sklearn.feature_extraction.text import TfidfVectorizerdef get_top_words(documents, top_n):
'''
function to get top tf-idf words and phrases
''' vectoriser = TfidfVectorizer(ngram_range=(1, 2),
max_df=0.5) tfidf_matrix = vectoriser.fit_transform(documents) feature_names = vectoriser.get_feature_names() df_tfidf = pd.DataFrame() for doc in range(len(documents)):
words = []
scores = [] feature_index = tfidf_matrix[doc,:].nonzero()[1]
tfidf_scores = zip(feature_index, [tfidf_matrix[doc, x] for x in feature_index]) for w, s in [(feature_names[i], s) for (i, s) in tfidf_scores]:
words.append(w)
scores.append(s) df_temp = pd.DataFrame(data={’word’:words, 'score’:scores})
df_temp = df_temp.sort_values(’score’,ascending=False).head(top_n)
df_temp[’topic’] = doc
df_tfidf = df_tfidf.append(df_temp) return df_tfidf
我们将我们的推文分组到分配给它们的主题中,以形成长文档,然后对它们应用上述函数,以找到每个主题中最重要的 10 个术语:
topic_docs = []
# group text into topic-documents
for topic in range(N_CLUSTERS):
topic_docs.append(' '.join(df[df['cluster']==topic]['text_cl'].values))# apply function
df_tfidf = get_top_words(topic_docs, 10)
我们将可视化结果:每个图表代表一个主题及其 10 个最重要的术语。条形越长,术语越有代表性:

每个主题中最具代表性的术语
我们可以围绕经济刺激方案(话题 0)、病毒检测(话题 3)和体育(话题 9)找出一些话题。稍后我们将对其他人做更多的调查。
主题紧密度
我们的话题有多好?这是一个重要的问题,因为我们正在对实时数据使用无监督技术(我们没有任何训练集)。我们所能做的就是将它们相互比较。我们假设“好的”主题在向量空间中更紧凑,也就是说,它们的文档向量比坏的更接近。为了评估这一点,我们将查看每个 Twitter 向量在其各自的主题中与主题向量的质心的接近程度。
我们通过对每个主题进行平均来找到向量的质心:
topic_centroids = []for topic in tqdm(range(N_CLUSTERS)):
X_topic = X_red[df.index[df['cluster']==topic]]
X_mean = np.mean(X_topic, axis=0)
topic_centroids.append(X_mean)
然后,我们计算每个 Tweet 向量到各自主题质心的欧几里德距离:
from scipy.spatial.distance import euclideantopic_distances = []for row in tqdm(df.index):
topic_centroid = topic_centroids[df.iloc[row]['cluster']]
X_row = X_red[row]
topic_distance = euclidean(topic_centroid, X_row)
topic_distances.append(topic_distance)
df['topic_distance'] = topic_distances
我们可以想象到主题质心的距离分布:

文档向量到各个主题质心的分布
分布越靠近图表左侧,主题越紧凑。题目 3、4、6、7、8 似乎是强有力的竞争者;8 是可悲的蔓延,表明缺乏一致的内容。
主题相似度
我们看了每个主题中的推文有多相似,但我们也可以看这些主题彼此有多相似。我们将在 10 个主题质心之间构建欧几里德距离矩阵,以找到主题平均值之间的距离。平均值越接近,我们期望主题之间的重叠就越多。
from scipy.spatial import distance_matrixdf_dist_matrix = pd.DataFrame(distance_matrix(topic_centroids,
topic_centroids),
index=range(N_CLUSTERS),
columns=range(N_CLUSTERS))

主题质心的距离矩阵
距离矩阵显示了所有主题之间的距离。单元格的颜色越深(数字越小),与其行和列对应的主题越接近。题目 3 和 7 或者 0 和 2 离得挺近的;话题 1 和话题 4 相距甚远;话题 8,家里的害群之马,和其他人加起来离所有人都那么远。
洞察力
感谢那些在前一部分与我一起坚持到底的人——这是一项艰巨的任务,但我们已经发现了一些有用的信息,所以让我们回顾一下。
题目是关于什么的?
顶部的术语为主题提供了一些非常需要的上下文,使我们能够非常合理地猜测每个主题(广泛地)在讨论什么:
- 话题 0 关键词: 联邦,特朗普总统,税收,刺激方案,阻止,经济刺激,药房,联邦医疗,机构分门别类,告诉联邦 最有可能的大概: 特朗普的冠状病毒刺激方案
- 话题 1 关键词: 劫持,劫持细胞,冠状病毒劫持,冠状病毒分类,温馨希望,newmusic,温馨,covid19 covid2019,会议取消,分类 covid 最有可能关于:人们分享关于 COVID 如何“劫持你的细胞”的知识,以及各种活动被取消
- 话题二关键词:福西冠状病毒,更糟的川普,年轻不惧,川普旅行,不惧冠状病毒,停杀,旅行禁令,好停,人民意见,不惧
最有可能的大概: 川普的旅行禁令 - 话题三关键词: 联邦、检测、疾病、税收、资源、能源、系统、实验室、削弱、倡导 最有可能的关于: 美国冠状病毒检测
- 话题四关键词: 唐知道,美国意大利,一级防范禁闭可怖,避风港,可怖,着实令人,测试设定,设定冠状病毒,冠状病毒 isn,延迟测试
最有可能大概: 意大利因疫情爆发而一级防范禁闭 - 话题 5 关键词: tweet covid,brand tweet,twitter suggest,建议适当,适当的方式,途径 brand,19 covid,19 mattgsouthern,mattgsouthern,加拿大官员 最有可能的大概: Twitter,显然是在给 brands 关于如何发布关于冠状病毒的建议
- 话题 6 关键词: wanna,na,ya,nasty,bunch,aint,coronavirus ain,tp,warn house,ko 最有可能的大概:这个不明显。我不得不看一些例子,发现这是关于冠状病毒的非新闻相关的一般话语。(例:如果你们这些讨厌的喝醉了的女孩在周六晚上爬遍浴室地板后会洗手,我们可能就不会陷入这种困境了。)那是一条真正的推特。)
- 话题 7 关键词: 网络安全,pmp,pmp ppm,项目管理,敏捷,machinelearning,ppm 项目管理,项目管理敏捷,敏捷网络安全,网络安全规划 最有可能关于:如何在 COVID lockdown 中有效地远程管理一个交付团队!
- 话题 8 关键词: 家三,值得一试,王牌认真,享受王牌,开始享受,他妈的开始,来他妈的,面对美国,预兆可能,可怕预兆 最有可能:……你猜得和我一样好。我们在上一节已经看到,这是一个弱主题。
- 话题 9 关键词: 男女,锦标赛,ncaa 男,daniele,daniele rugani,女,球迷冠状病毒,签名请愿,玩球迷,英超 最有可能关于:冠状病毒对世界体坛的影响,例如 NCAA,英国 PL 或达妮埃莱·鲁加尼,据报道病毒检测呈阳性的意大利足球运动员。
题目有多好?
- 关于测试(3) 、意大利封锁(4)、笑话推文(6) 、远程工作方式(7) 和世界体育(9) 的主题是最紧凑的,因此我们可以假设它们涵盖了比其他主题更简洁的主题。
- COVID 测试(3) 和远程工作方式(7) 密切相关——我的理论是这是由于分别有实验室和网络等重叠的技术术语。
- 特朗普的 COVID 刺激方案(0) 和他的旅行禁令(2) 也密切相关,原因显而易见。
- 从语义上来说,病毒的生物工作方式(1) 和意大利封锁(4) 相距最远。
通过从大量真实数据中提取一些连贯的主题,我们使用最先进的语言模型展示了较少采用的主题建模方法的有效性。我们的方法还允许我们评估我们的主题之间的关系,这似乎与我们对它们的解释相一致。我认为这是一次成功。
事后思考
我做错什么了吗?我能做得更好吗?我做得好吗?
请随时在 LinkedIn 上联系我;如果你对我的工作感兴趣,我总是很乐意接受挑战或者只是聊聊天。
新冠肺炎失业简报:州、种族和行业
自 2008 年金融危机以来,新冠肺炎一直是对美国劳动力市场影响最大的国家。
面对快速传播的疾病,大量来自各级政府的错误信息,国家经济收缩,企业暂时或永久关闭。显然,经济的某些部门在应对病毒时受到了不同的打击,本文将从三个横截面国家、种族和行业来探讨【2020 年 1 月至 6 月的就业趋势。
该分析的数据来自劳工统计局。你可以在 my github repo 下载数据并查看 python 笔记本。
这个笔记本描述了几个查询美国劳工统计局 API 的例子,并把数据整理成一个…
github.com](https://github.com/rchardptrsn/COVID-Employment-Analysis)
州失业率


一些州从新冠肺炎疫情爆发后下意识的就业市场崩溃中复苏的速度较慢。内华达州在酒店和休闲行业拥有近 30 万名工人,失业率在 2020 年 4 月达到 30%。

人种
不幸的是,劳工统计局只根据黑人、亚洲人和白人来划分每月的失业率。尽管这些类别有限,但很明显,黑人的复苏没有白人强劲。

工业
各行业的就业水平受到社会距离限制和旅游指南的强烈影响。休闲和酒店等行业不要求大多数员工拥有高等学位或证书,因此可以认为它们对需求下降的反应更有弹性。运输和仓储也受到重创,可能是因为旅行限制和贸易放缓。

从数据中可以明显看出,新冠肺炎并没有平等地影响所有经济部门。为了度过这个疫情,我们必须调整我们的生活方式,确保我们把社会的健康和福利放在自己之前。我们不能忘记2020 年上半年因致命病毒而失去工作的数百万人,我们可以支持那些受戴口罩和社会距离影响的人。
新冠肺炎对数据科学领域的影响及我们的对策

新冠肺炎危机中的英雄是医生和护士、急救人员、杂货店工人和其他基本服务提供者,他们在疫情期间得到了前所未有的需求。
虽然更多是在幕后,但另一个群体也在名单上:数据科学家。全球成千上万的科学家正在收集和梳理数据,以更好地了解病毒,跟踪其传播,开发药物,以及分析疫情对经济、供应链和我们生活的其他方面的影响。
当然,早在冠状病毒来袭之前,数据科学就已经有了辉煌的时刻。数据已经变得无处不在,云计算和机器学习等创新正在提供新的机会来挖掘数据以获得可操作的见解,并实现预测性和规范性分析。因此,每个行业都在增加其定量劳动力。
这造成了日益严重的技能短缺。根据科技职业网站 Dice 的一份报告,数据工程师是去年科技行业增长最快的工作,空缺职位数量增长了 50%。领英 2018 年 8 月的一项研究发现,美国短缺超过 15 万人。
随着新冠肺炎进一步提高数据科学的重要性和兴趣,培养新的数据科学家的需求变得更加迫切。这将需要改变-不仅仅是更好的教育和培训计划,还需要重新评估是什么造就了顶尖的数据科学家以及在哪里可以找到他或她。
世界应该有哪些不同的做法?我有三个想法。
1.超越传统的技能组合。
在雇用数据科学家时,大多数组织都寻求拥有应用数学、统计学、计算机科学、工程学或任何其他需要定量分析的学位或经验的人。这很有道理,但我们应该尽可能想象好的数据科学家来自哪里。例如,缺少一个好的学位不应该是一个阻碍。
我有高等学位,但我不是从数据科学家开始的。我的学士和硕士学位是在航空航天,航空和航天工程。
但在我读硕士期间,我被选中参加了一个远离火箭科学的项目:开发新的多通道测谎仪技术,该技术至今仍在使用。在这项需要开发算法和机器学习模型来检测测谎仪测试中的异常的数据密集型工作中,我意识到我找到了自己的激情:数据科学。从那以后我就一直在这个领域工作。
故事的寓意:数据科学家可能不总是来自典型的人才库。任何拥有将数据与见解联系起来的动力和知识的人都非常适合。
2.已经够了:让更多的女性进入这个领域。
虽然工作场所的性别平衡在过去几十年里有了显著改善,但女性在技术领域的比例实际上有所下降。根据国家妇女信息技术中心的数据,该行业的女性人数在 1991 年达到顶峰,占 36 %,此后一直下降。分析洞察说在数据科学和其他面向数据的工作中,女性不到三分之一。
我对技术领域的这种性别差距太熟悉了。在大学工程项目的第一年,我是 400 名学生中的 10 名女性之一。我记得我小时候的老师鼓励男孩学习数学和科学,鼓励女孩学习艺术和社会学。在小学时,我是数学奥林匹克的唯一女性参与者。
是时候停止疯狂了。在这个世界需要尽可能多的数据科学家的时候,让我们停止用可能让女性感到不受欢迎的公开行为或隐蔽信息将一半人口从这个领域推开。
3.寻找饥饿和好奇的人。
为了数据科学而数据科学不是很有用。数据科学家可能是技术神童,拥有关于算法、模型和编程的丰富知识,但除非他们有强烈的动力去发现隐藏在数据中的模式,以收集有价值和可操作的见解,并将它们转化为规定性分析以支持决策,否则他们只是在玩工具。
从服务经历数字化转型的行业到研究流行病,最好的数据科学背后都有真正的使命和目的。你需要首先关注手头的问题,然后像数据科学项目一样,将它分解成你可以解决的不同的、可解决的元素。
我曾经在一次求职面试中被问及我对什么充满热情,我谈到了我对历史的毕生热爱——我发现研究过去是多么令人兴奋,历史就像多维度的时间序列数据,就像我们在数据科学中所做的那样,发现可以揭示未来教训的模式。它帮我找到了工作。
我的观点是,对于组织来说,对他们招聘的数据科学家的类型要有思考力和创造力,这很重要,这意味着也要将数据科学视为一门艺术。好奇心很重要。对解决问题的痴迷很重要。这些天生的品质是教不来的。数据科学特定技能可以。
我们生活在一个充满挑战的时代,数据科学从未像现在这样有价值。让我们确保吸引最优秀、最聪明的人到这个领域来……以我们需要的高数量。
错综复杂的联系追踪应用程序正在出现
这是经济复苏所必需的,它很乱,可能已经在你的口袋里了

亚马逊远程助手图片,鸣谢:亚马逊
在美国,只有三个州表示有兴趣采用早在三月份宣布的苹果-谷歌联系追踪平台。相比之下,英国放弃了创建定制 COVID 联系人追踪应用程序的计划,而是将使用苹果-谷歌平台。英国的决定逆转之前,初步试验发现政府的中央系统只能检测到 4%的 iPhones。尽管如此,解决方案在冬季之前不会上线,当它发布时,可能仅限于症状报告。这是因为政府的测试和追踪项目负责人还不相信这项技术适合使用。
“在过去的几周里,我们一直在为零售商开发碰撞检测系统……人们走到一起,呆在一起。因此,我们需要找出症结所在,”一家物联网供应商表示
尽管围绕无数接触者追踪和新冠肺炎安全措施缺乏标准化,对隐私的担忧,最终用户采用的缺乏,随着城市放松限制和企业重新开业,私营行业并没有等待万灵药。
据负责机器人和工程的副总裁布拉德·波特发布的公司公告称,亚马逊刚刚推出了一个解决方案,该方案将人工智能和机器学习应用于他们大楼的摄像机镜头,以识别高流量区域,从而改善员工的社交距离。这个名为“距离助手”的解决方案现在已经在他们的几栋建筑中使用,他们计划开源这个软件。
其他雇主正在探索如何利用基于应用的位置数据、运行在 Android 和 iOS 上的消费者移动应用以及物联网(IoT)信标来提高安全性和支持经济复苏。“零售商正在询问我们如何维护更安全、更高效的环境,”Acuity Brands 高级副总裁 Audwin Cash 表示,Acuity Brands 是一家面向零售、机场和工业企业的物联网位置服务提供商。
像 Acuity 这样的解决方案通常用于店内导航:那些为室内顾客提供路线指导的“蓝点寻路”应用程序,或者商店员工从货架上快速挑选产品以进行“点击取货”订单。它们还可以用于提供匿名的总客流量分析,帮助公司了解客户或员工在哪里花费的时间最多(或最少),这有助于改善营销决策。
但是最近,对话发生了变化。
“在过去的几周里,我们一直在为零售商开发碰撞检测系统。这项测试现在使用购物车,但也可能用于员工。人们聚在一起,待在一起。所以,我们需要找出症结所在,”卡什说。
这些夹点可以在热图上以彩色花朵的形式表示,热图是企业用来匿名观察人口密度和遵守社交距离准则的图形仪表盘可视化,或者根据高流量确定应该清理的区域。
亚马逊推出“远程助手”,鸣谢:亚马逊
恢复需要大规模的接触追踪
约翰·霍普金斯彭博公共卫生学院的一份报告概述了缓解美国重返工作和学校的社会距离的要求,更重要的是,推动经济发展。在最优先的事项中,他们的卫生专家表示,美国需要 1)快速诊断测试的便捷途径,2) 免疫识别,以及 3)追踪报告病例的所有接触者的能力,以识别和警告那些可能接触过新冠肺炎的人。
挑战在于如何大规模实现接触追踪。为了支持这一需求,约翰霍普金斯大学估计需要 36 亿美元的紧急资金和 10 万额外的人。
根据国家公共电台的调查,目前的 37,110 名接触者追踪人员仍然远远不能满足这一需求,并且考虑到他们目前的病例数,只有 7 个州和哥伦比亚特区有人员控制疫情。
“想象一下,如果一名员工报告说他们生病了,那么我们就可以确定还有谁和他们一起轮班,”Cash 说。
为了利用技术大规模解决联系人追踪问题,苹果和谷歌宣布建立合作伙伴关系,提出一种去中心化的模式。他们的解决方案利用智能手机上的蓝牙来记录使用同一平台的其他设备,如果它们距离很近的话。如果一个人冠状病毒测试呈阳性,它将提醒任何其他人在 14 天内遇到他们。

但是苹果-谷歌系统是如此的封闭,以至于卫生官员说该软件将没有多大用处,只有阿拉巴马州、南卡罗来纳州和北达科他州确认使用该技术。其他 16 个州完全排除了联系人追踪应用的开发。
“我认为,如果你问大多数人,‘你相信谷歌会尊重你的隐私吗?’。。。他们不信任谷歌,”共和党参议员比尔·卡西迪说,他是 6 月份公布的监管联系人追踪应用程序的两党提案人。
除了全球官员的怀疑,这种方法还面临着任何移动应用程序的另一个障碍:认知度和采用率。华盛顿邮报-马里兰大学的一项调查发现,一旦苹果-谷歌联系人追踪应用发布,近五分之三的美国人不愿意或无法下载,43%的人普遍怀疑科技公司保护个人隐私的能力。
根据牛津大学的一项研究,这还不够。为了有效阻止疫情,研究人员确定至少 60%的人口需要使用数字接触追踪应用程序。
政府措施无效
然而,一个例外是越南及其 9500 万人口,到目前为止,越南没有因冠状病毒而死亡的,这主要部分归功于全国性的强制接触者追踪计划。他们的严格版计划在印刷品和电视上公开患者的身份,以告知公众受试者以前的目的地,这样,如果公民在同一时间访问过,他们可以联系当地的卫生当局。
如果每个州使用不同的协议开发联系人追踪应用程序,那么对于跨州旅行的公民来说,互操作性就成了一个问题。

照片由埃里克·麦克莱恩拍摄
在新加坡,当局推出了首批联系人追踪应用程序之一,接受率仅达到 20%。在挪威,21%的采用率仅略高于此。
在美国,强制性的项目是完全不可能的,而且病人身份的公开会与许多隐私法和健康法规相冲突。但是对于那些通过移动应用程序实施某种形式追踪的州来说,挑战在于一致性。如果每个州使用不同的协议开发联系人追踪应用程序,那么对于跨州旅行的公民来说,互操作性就成了一个问题。
一些政府仓促行事,跌跌撞撞,然后努力却未能赢得公众信任。对北达科他州和南达科他州的 Care19 移动追踪应用程序发布后的分析发现,通过与 Foursquare 共享公民位置和其他个人数据,违反了自己的隐私政策。Foursquare 通过一名发言人表示,他们“没有以任何方式使用这些数据,这些数据很快就会被丢弃”,根据最先发现这一问题的分析师的说法,这一数据泄露事件已于 6 月份在关闭。
私营部门对安全和接触者追踪的做法
雇主们不能再等了,正在研究其他方法来实现复苏:最初是在上班前进行体温检查和员工自我调查。
零售业现在有一种甚至是医疗行业都缺乏的能力:每天有数百万人使用的 iOS 和 Android 上的位置感知应用程序可以支持联系追踪。
可穿戴设备制造商 Fitbit 最近发布了一个结合健康指标、症状检查和问卷调查的解决方案。根据 Fitbit health solutions 的网页,他们的 Fitbit Care Ready for Work 项目面向雇主,雇主可以查看仪表盘来监控员工重返工作岗位的准备情况,这有助于为工作场所协议、业务连续性和公司风险状况提供信息。

利用移动应用程序和生物识别设备可以提供比现场温度检查更高级的警告。斯坦福大学基因组学和个性化医学中心主任迈克尔·斯奈德博士在 Fitbit 的公开声明中说:“可穿戴设备非常强大,因为它们可以测量生物特征的细微差别,这些细微差别可能表明常规医生诊所就诊时无法检测到的疾病发作。”。“在测量心率时,即使每分钟心跳增加两次,也可能表明免疫系统有明显反应,这就是为什么可穿戴设备可以成为评估员工准备重返工作时整体健康状况的重要工具,特别是在评估有症状和无症状的新冠肺炎病例时。”
与亚马逊使用摄像机相比,早期的 Acuity 飞行员使用 iOS 或 Android 智能手机检测碰撞和集群,这些智能手机与天花板上的智能照明网络通信。
这引发了新的对话,有可能在工作场所接触到 trace。“找到聚集在商店里的员工是一种可能。我们正在探索性地讨论如何扩展这一场景,“共享现金”。“想象一下,如果一名员工报告他们生病了,然后我们可以确定还有谁和他们一起轮班。”
一种新颖的方法怎么样:位置感知移动应用
雇主们正试图解决社交距离问题,但他们的联系追踪解决方案仍然只通知那些在工作场所的人。准确跟踪办公大楼外的位置和联系仍然是经济发展的一个挑战。此外,随着越来越多的工人转向在家工作,这些解决方案不太可能在工厂、制造设施和配送中心之外产生影响。
企业可以解决采用挑战、大规模匿名追踪,并为经济带来更广泛的影响,因为零售业现在有一种甚至医疗保健行业都缺乏的能力:每天有数百万人使用的 iOS 和 Android 上的位置感知应用程序,这些应用程序可以支持联系追踪。
这些移动应用程序不会用于传输个人身份(PII)或健康信息(PHI),而是仅限于位置数据和匿名设备标记。相比之下,Fitbit 向云端传输的个人数据更多。

马库斯·温克勒在 Unsplash 上的照片
担心从手机上共享移动位置数据?你现在就做。零售应用主要用于浏览产品、管理购物清单和订单提货。Kroger iPhone 应用程序在设置页面中解释说,启用位置跟踪“可以实现更流畅、更高效的提货体验和个性化的店内购物。”使用地理围栏和室内定位,他们还通过导航(“寻路”)引导客户找到产品,或通过个性化报价通知客户。
例如,当你走过麦片货架时,玉米片的应用内折扣可能会激活。通过使用与苹果 iOS 或安卓移动设备通信的蓝牙信标或智能照明网络,一些定位系统可以实现高达 4 英寸的定位精度。然后,实时数据被吸收到高级数据模型中,以产生高度个性化和位置相关的报价。许多应用程序还通过 GPS 或 WiFi 使用位置跟踪,并可以在用户同意的情况下在商店内外的后台运行。
那么,如果一个零售商联盟匿名化他们的客户定位数据,并在公共健康危机中使用人工智能,而不是在移动设备上使用该技术来获得位置感知的数字优惠券,会怎么样?想象一下,塔吉特、沃尔玛、克罗格、沃尔格林、CVS 和其他主要零售商通过数据共享合作开展回归商业活动。
零售商拥有基本要素:1)数百万忠实客户,2)苹果和谷歌 Play 应用商店提供的位置感知移动应用程序,3)共享匿名位置数据的许可,以及 4)他们是值得信赖的品牌,每天为数百万人提供杂货和健康需求。
批准了吗?
鉴于零售已经提供了安全指导,扩大了招聘,对基本商品的销售保持开放,并正在进行 COVID 测试以填补公共空白,与科技巨头相比,获得用户对匿名位置数据共享的采用和同意可能并不那么困难。
人们相信沃尔玛、CVS 和沃尔格林每年能为30 亿张处方配药。作为基本商品和服务的提供者,他们中的许多人甚至在隔离检疫之前就已经被消费者依赖来提供食物和健康咨询服务。如果沃尔玛继续在佐治亚州的铺开,它可能会成为你新的值得信赖的慢性和急性医疗保健提供商。

沃尔玛健康诊所(来源:沃尔玛)
考虑现有的用户群;CVS 拥有 6200 万名忠诚计划会员。沃尔格林在 2019 年超过了5000 万应用安装量,其中有 9000 万忠诚计划会员。在美国零售巨头沃尔玛,每周有近 2 . 65 亿人访问他们的商店,每月有 8605 万用户访问他们的应用。即使主要零售商之间存在客户重叠,这也是应用采用的巨大基础。
与苹果的应用程序或政府主导的场景相反,最终用户可能会被鼓励根据个人偏好和对每个组织的隐私政策的舒适度,在零售合作伙伴级别选择加入(或退出),类似于在 ios 中应用个人设置以通过应用程序进行通知或位置跟踪的方式。
尽管如此,这仍需要对匿名合作伙伴信号进行集中管理,并为用户输入和管理其 COVID 相关测试提供安全界面。
如果不是苹果-谷歌,这就引出了一个问题:谁可能成为商业合作伙伴的集中枢纽,获得大量移动遥测数据。“迄今为止,大多数零售商都避开了顾客数据和任何与 PII 有关的东西。卡什说:“要让这种事情发生,你需要一个可信的第三方来仲裁数据交换。”
那会是谁呢?《华盛顿邮报》和马里兰大学的民意调查对此有所启发。调查受访者表示,在保护联系人追踪应用程序的匿名性方面,大学(56%)和公共卫生机构(57%)的信任度高于科技公司(43%)。
因此,如果零售消费者健康公司与可信的公共卫生机构合作,它们或许能够解决接触者追踪的一个重要需求:匿名收集的位置数据。
隐私第一
仅仅因为我们有能力,并不意味着我们应该不顾一切。要实现这一点,有几个技术、伦理和法律方面的考虑。从 GPS 到蓝牙、WiFi 和可见光通信,存在不同的技术,每种技术都有不同程度的准确性。有些,像 GPS,在室内并不总是一致的。
接下来,不应轻视同意和隐私。大多数应用程序都有条款和条件条款,授予发布者与第三方共享数据的权利。然而,这通常仅限于营销目的或利用诊断数据优化应用体验。
Fitbit 的隐私政策确实包括通知用户,他们的去身份数据可能会被用于研究,例如在一项为期两年的研究中使用的那种数据,该研究确定了使用可穿戴设备对流感样疾病进行实时监测的改进。
“我认为,如果你问大多数人,‘你相信谷歌会尊重你的隐私吗?’。。。他们不信任谷歌。"
立法者想要更进一步。“暴露通知隐私法案”将要求公司开发接触追踪应用程序,与公共卫生官员合作。它还规定收集的数据不得用于商业目的,并允许用户随时删除他们的数据。
最后,这种挑衅只能用以下原则来探讨:解决方案必须首先寻求“不造成伤害”,它必须只用于接触意识的目的,它必须保护用户的权利和隐私,它必须匿名化他们的身份。但是,如果在道德和安全的条件下进行管理,零售商和卫生合作伙伴的联盟可以使用标准化的接触追踪方法加快经济回报。
Covid 死亡预测不断变化是我们的错
这么多缺点,这么少时间
5 月 4 日,华盛顿大学的健康指标和评估研究所 (IHME)更新了用于预测美国 Covid 相关死亡的估计框架。在他们的站点上报告的实质性变化反映了与社会距离政策相关的流动性,修正了报告的病例,以说明增加的检测和驱动因素,如温度、人口密度和人均检测。
他们还将死亡人数上调至 134,475 人。就在 3 天前,这一数字为 72,433。
事实是,美国政府和卫生官员所依赖的 IHME 预测自 3 月以来就像坐过山车一样,只是不明显。
由于 IHME 网站上的预测可视化是动态的,普通访问者很难看到这些随时间的波动。而且,大多数新闻周期只报道最近的 delta,这也无助于问题的解决。由于 IHME 没有提供他们的可视化档案,我使用了他们免费提供的数据制作了下面的预测死亡时间图。

数据来源:IHME 图片来源:大卫·莱博维茨
以“相同的数字”结束
在 3 月 30 日的新闻发布会上,冠状病毒应对协调员 Deborah Birx 博士提到了 12 个已经接受审查的全球模型。虽然没有分享原因,但他们排除了这些原因,而是“从头”开发了一个新模型,随后了解到来自 IHME 的研究。Birx 博士最终预测了 IHME 的未来,因为他们“最终的数字是一样的”
自那以来,政府和卫生官员一直依赖 IHME 模型进行冠状病毒规划,扩大社会距离指导方针,制定遏制战略,最近还计划在州一级放松就地安置限制,以支持经济复苏。由于 IHME 修改了他们的数据,他们对最好情况的预测在新闻发布会上被重复。
例如,在 5 月 1 日的新闻发布会上,唐纳德·特朗普总统在谈到冠状病毒时说,“希望我们的死亡人数低于 10 万人”,指的是平均预测的上限。就在 4 天前,政府公布的平均死亡人数超过了 70,000 。两周前的 4 月 20 日,这个数字是 60,000 。都是基于 IHME 模型。
虽然对感知的门柱运动可能有合理的担忧,但它转移了更深层次的问题:我们中很少有人(从行政部门,到新闻媒体,到每个社交媒体扶手椅数据科学家)一直在仔细检查足球场本身。
因此,通过省略,大多数新闻报道,新闻简报和死亡预测的盲目推特都可以被解读。
这是怎么回事?
IHME 模型利用来自全球各地的数据,以及假设遵守美国的应对策略(学校关闭、就地安置命令、非必要的商业关闭)来预测峰值医疗需求和预测死亡人数。既然 IHME 提供的学术分析部分由知名慈善家资助,我就用马文·盖的话说,“到底怎么回事?
“IHME 的预测不是基于传播动力学,而是基于一个没有流行病学基础的统计模型。”
有几个因素需要考虑。首先,正如《内科医学年鉴》所言,“IHME 的预测不是基于传播动力学,而是基于没有流行病学基础的统计模型。”他们没有使用流行病学学科,而是选择基于中国武汉的病例和死亡轨迹以及意大利和韩国的指标建立模型。
第二,IHME 使用了过于乐观的预测,以至于模糊了一些相当复杂的假设和限制,其中一些在 3 月底和 4 月初的美国并没有得到一致执行。正如你将在下面的截图中看到的,描述、上下文和可视化格式一直在变化。
最后,我们应该受到责备,因为我们盲目地抓住标题上的 ,而没有仔细检查来源和要求上下文。
为 IHME 说句公道话,spartan projection 页面包含了每款车型变更的公布结果,并提供了更新说明的链接。但我怀疑,对报告的审查与软件更新前的 iOS 许可协议一样严格。像许多申请条款一样,我们只需滚动到底部,点击“同意”,就可以进入下一步了。然而,问题在于所有这些细节和假设,尤其是当目标和背景不断变化的时候。
例如,请注意这张 5 月 1 日 IHME 预测页面的截图。过度宽泛的免责声明“在感染最小化和控制实施之前保持社会距离”显示在文件夹的顶部。

作者截图 IHME 新冠肺炎预测(截至 2020 年 5 月 1 日)
但是在 5 月 4 日,修正后的模型预测几乎是几天前预测的两倍,没有任何警示性的假设。他们还选择平滑可视化,而不是之前基于报告滞后的直线图。

作者截图 IHME 新冠肺炎预测(截至 2020 年 5 月 4 日)
利用中国的应对策略预测美国的结果
在 3 月 27 日发表的第一篇论文中,IHME 概述了对呼吸机需求和医院床位过剩的初步预测,以及超过 81,000 人的死亡预测。当该模型首次推出时,美国许多州尚未实施社交距离政策,那些实施的州也不一致。尽管如此, IHME 利用来自其他国家(主要是中国和意大利)的趋势、预测和死亡人数来预测美国的结果。
但每个国家对冠状病毒的反应不同,速度和效果也不同。与美国相反,中国行动迅速:他们有现成的免费检测,建立了 1000 个床位的医院,制定了快速检测方案,在武汉等热点地区停止公共交通,强制隔离,并试图追踪接触者。所有这些举措在病毒在美国爆发时都是不可能的。
截至 5 月 4 日,IHME 似乎终于收到了消息,承认,“越来越清楚的是,新冠肺炎疫情轨迹——以及相应的反应——在世界各地高度可变。”丫的,觉得怎么样?
其次,他们用来预测美国死亡率的国际死亡人数并不完全准确。意大利一直被无辜地低估了死亡人数,因为许多人没有被送往医院或接受检查就死亡了。相比之下,正如美国中央情报局官员在《纽约时报》的一次曝光中所称,小说作品正从中国流出。在信中,他们声称中国一直在大幅少报冠状病毒感染,因为中国的中层官员害怕受到惩罚,一直在感染率、检测和死亡人数上撒谎。
无论是由于疫情战争迷雾中的诚实错误,还是有意的谎言,问题仍然存在:看不见的和未统计的死亡没有被包括在 IHME 直到四月中旬的预报中。
不现实的乐观
尽管这些早期的挑战,IHME 已经受益于时间来提高预测的准确性:他们现在使用约翰霍普金斯大学(JHU)的实际死亡人数,并包括州级社会距离测量的假设。
因此,4 月 17 日的预报带来了一些更新,正如他们宣称的那样,带来了模型的“实质性”改进。这也是他们预测的迄今为止最低的死亡人数(60,308 人)。
这遭到了一些质疑。
当时, IHME 模型被福布斯称为“ 不切实际的乐观,而纽约时报认为,与哥伦比亚大学、东北大学和其他机构的基于流行病学的模型相比,“不那么悲观”。
尽管为重新开放策略和每个州可能放松限制的日期提供了非常规范性的指导,IHME 在他们的预测中根本没有应用这些。
4 月 17 日的更新也为各州提供了放松社交距离限制的指导。例如,他们建议纽约、新泽西和康涅狄格最早可以在五月底考虑放宽社交距离。

来源:IHME 2020 年 4 月 17 日估计更新
但是,尽管为重新开放策略提供了非常规范性的指导,以及每个州可能放松限制的日期,IHME 实际上根本没有在他们的预测中应用这些。根据他们的常见问题解答,截至 4 月 17 日,他们的预测“不再考虑社交距离任务的可变性”。
相比之下,宾夕法尼亚大学沃顿商学院(Wharton School of the University of Pennsylvania)开发了一种建模工具来可视化各州重新开放的健康和经济影响,称为冠状病毒政策响应模拟器。他们将该工具描述为使用“流行病学框架和经验估计来模拟放松国家封锁政策的健康和经济影响。”
如果各州开始部分重新开放,沃顿工具预测,除了 115,937 例 Covid 相关死亡的基线外,还有 43,683 例死亡。他们将部分重新开放定义为解除紧急状态声明、在家呆着的命令和学校关闭。
模拟器进一步预测,如果取消所有限制,包括取消除部分重新开放标准之外的商业和餐馆限制,到 6 月 29 日,死亡人数将增加 222,823 人(总数为 338,760 人)。
一些预测者采取了不同的方法来预测信心,以解释 IHME 的乐观情绪。德克萨斯大学奥斯汀分校的一个财团审查了 IHME 模型,目的是使用 GPS 信号模式而不是使用其他国家的趋势来校正它。在他们的研究过程中,他们注意到IHME 模型显示** 越是展望未来就越能增加确定性。换一种方式来说,人们可能会对预测近几英寸的降雨量有更高的信心,而不是预测未来六周的降雨量。**
这可能是东北大学只会提前两周预测死亡人数的原因。相比之下,IHME 声称从开始到 8 月 4 日已经进行了四个月的预测。尽管连日期都不确定。尽管保留那个日期,因为我们稍后将回到它。

东北大学网站作者截图(2020 年 5 月 2 日)
背景很重要:“低于 10 万英镑”..到什么时候?
想想其他疾病和疾病的预测是如何发布的:疾病预防控制中心估计,在 2017-2018 流感季节期间,美国有 61,000 人死于流感,并声称每年有 647,000 美国人死于心脏病。它们包括一个时间段。
但是参考 Covid,通常省略相同的基于持续时间的上下文。在很大程度上,头条新闻和简报只是简单地陈述了总死亡人数。例如,美国新闻&世界报道在 4 月 6 日的一篇文章中吹捧较低的预测,称“新的评估预测大约 81,766 人死亡。”NPR4 月 9 日,以“冠状病毒死亡人数可能更像 6 万人”为标题这两个故事都没有提到那个时期。
回想一下,在 5 月 1 日的新闻发布会上,总统的声明也没有澄清时间,“希望我们的死亡人数低于 10 万,尽管这是一个可怕的数字。”
想想来自 IHME 本身的报道。他们在 4 月 5 日的新闻稿中声称,“IHME 预测死亡人数为 81766 人,范围在 49431 到 136401 人之间。”在这份 780 字的声明中,没有对死亡人数的日期范围或波动进行限制。这是夏末的天气预报吗?12 月 31 日?隔离的终结?
因此,通过省略,大多数新闻报道,新闻简报和死亡预测的盲目推特都可以被解读。
所以,问问你自己这个问题:当你阅读这些报道,或者在 3 月和 4 月的预测中提到的类似报道时,你认为它们是什么意思?疫情持续期间或疫苗研制出来之前的死亡人数可能是可信的答案。另一个合乎逻辑的含义可能是截至 12 月 31 日的一年,或者是一个季节,与类似流感的统计数据保持一致。
但是这些假设都不是真的。
据《IHME》报道,那里的 是 预测的结束日期,一些新闻媒体已经开始关注这一消息。在 Forbes 文章中,他们称,“根据 IHME 模型,到 2020 年 8 月 4 日疫情将接近尾声”,“到那时,每日死亡率将降至零。”他们使用这个日期大概是因为图表上标有“预计到 2020 年 8 月 4 日”
但更奇怪的是,为期四个月的预测“8 月 4 日”实际上将于 7 月 6 日结束。当你看到我从 IHME 网站上想象出来的这个形象时,请让这一点沉淀一会儿。

作者生成的图片来自 IHME 网站(2020 年 5 月 1 日)
动画显示(截至 5 月 1 日,当我在上面抓图时)在美国,我们将在 7 月 6 日达到 72,433 的最大预计死亡人数,然后一直到 8 月 4 日。如果你认为这意味着 7 月 6 日之后不会再有死亡预测,那么你就完全同意 IHME 的观点。
5 月 4 日的更新在此基础上略有改进,取消了 IHME 自 3 月 28 日以来一直使用的平线结果。正如你在下面的截图中看到的,这将 7 月 6 日的预测调整为 130,255 人死亡。或者换句话说,在预测死亡人数(134475)的 96.9%以内。按照这种逻辑,他们假设在从 7 月 6 日到 8 月的近 30 天内,只有 4220 人会因冠状病毒而丧生。

作者生成的图片来自 IHME 网站(2020 年 5 月 4 日)
IHME 在他们的论文中详述了他们的逻辑,指出新冠肺炎的死亡率将在五月或六月下降到百万分之 0.3 以下,因此在统计上不再重要。
更简单地说,他们在他们的常见问题中解释说,“假设当前的社会距离措施保持不变,直到感染最小化,遏制战略得到实施(作者注:之前报道过,现在已从预测页面中删除),我们的模型预测,到这个日期在你所在的地方,新冠肺炎的死亡人数将接近于零。”这不仅是一个慷慨的免责声明,它还允许众所周知的目标不断移动。还记得德克萨斯大学研究所提到的关于未来预测确定性的说法吗?
与 IHME 预测的新冠肺炎死亡率相比,CDC 发现流感的死亡率为每 100,000 人口中有 2.0 人死亡。尽管流感的发病率已经超过了整个季节,而且 Covid 的假设是,在它的周期结束时,发病率将会显著下降,但这似乎仍然令人怀疑。对于流感,测试和流感疫苗都可以广泛获得。对于 Covid,我们两者都没有。假设仅仅是社会距离就能在两个月内使这种侵略性病毒的死亡率低于流感,这是值得怀疑的。
其他奇闻
你在上面的死亡预测虚线图周围看到的阴影带显示了预测范围的上下限。尽管这是合理的,因为预报由于其不精确的性质将包括范围,但有趣的是,在 4 月 27 日,超过 56,000 人死亡,然而 IHME 同一日期预报范围的下限奇怪地位于 56,563。4 月 29 日,平均预测的下限是 59343 人,尽管 JHU 报告的死亡人数超过了** 6 万 。这就像天气预报员预测当天的温度在 45 到 67 度之间,而在他的直播中,外面的温度是 29 度,还下着雪。**

数据来源:IHME(2020 年 5 月 1 日)
驾驭预测浪潮
有趣的是,一个新的短语不时出现在 IHME 死亡预测中,尽管没有显示在他们的预测页面上。这个术语现在指的不是八月份的死亡人数,而是第一波病毒。
然而,IHME 报告并没有对波给出明确的定义,并且没有上下文允许目标也在这里改变。第一波可能包括一系列需要满足的条件,如冠状病毒病例在一段时间内的下降趋势,或传播速度。第一波可能是大多数州重新开门营业的时候。没有定义,它可能是任何东西。
值得注意的是,随着 5 月 4 日最近的模型变化,更新页面的解释,以及投影可视化现在明显缺少单词“wave”或短语“first wave”
第一波确实有可能是 IHME 在三月份定义的任意的四个月窗口(截止于 8 月 4 日)。他们毕竟创造了这个短语。他们不会使用未来滚动期预测(如东北大学的两周展望),而是会继续更新他们对 8 月 4 日或某个任意波动结束条件的预测。所以最后,死亡预测总是准确的。
这就像在足球比赛的最终比分上下赌注,并在每次触地得分和每个球员受伤后更新您的赌注。要是我的经纪人能给我这样的自由就好了。我的预测将是完美的。
(编辑于 5.16.20:更正了指向《纽约时报》文章的超链接)
关于新冠肺炎的 CT 扫描数据集
促进人工智能研究使用 CTs 对抗新冠肺炎病毒
(数据可在https://github.com/UCSD-AI4H/COVID-CT获得)
截至 2020 年 3 月 30 日,冠状病毒疾病 2019(新冠肺炎)已影响到全球 775,306 人,并导致 37,083 人死亡。控制这种疾病传播的一个主要障碍是检测的低效和短缺。目前的测试大多基于逆转录聚合酶链反应(RT-PCR)。需要 4-6 小时才能得到结果,与新冠肺炎的快速传播速度相比,这是一段很长的时间。除了效率低下,RT-聚合酶链式反应测试试剂盒严重短缺。
这促使我们研究替代的检测方式,这可能比 RT-PCR 更快、更便宜、更有效,但与 RT-PCR 一样准确。我们尤其对 CT 扫描感兴趣。已经有几项研究 CT 扫描在筛查和检测新冠肺炎中的有效性的工作,并且结果是有希望的。然而,出于隐私考虑,这些作品中使用的 CT 扫描并不与公众分享。这极大地阻碍了更先进的人工智能方法的研究和发展,以更准确地测试基于 CT 的新冠肺炎。
为了解决这个问题,我们建立了一个 COVID-CT 数据集,其中包含 275 次新冠肺炎阳性的 CT 扫描,并对公众开放源代码,以促进新冠肺炎基于 CT 的检测的 R&D。从 760 份关于新冠肺炎的 medRxiv 和 bioRxiv 预印本中,我们提取报道的 ct 图像,并通过阅读这些图像的标题来手动选择那些包含新冠肺炎临床发现的图像。下图显示了数据集中的一些示例。

我们数据集中的新冠肺炎联系类型示例。
我们在 183 个 COVID ct 和 146 个非 COVID CT 上训练了一个深度学习模型,以预测 CT 图像是否对新冠肺炎呈阳性。我们的模型在 35 台 COVID CT 和 34 台非 COVID CT 上进行了测试,F1 得分为 0.85。结果表明,CT 扫描是有希望的筛查和测试新冠肺炎,但需要更先进的方法来进一步提高准确性。
数据和代码可在 https://github.com/UCSD-AI4H/COVID-CT获得
更多详情请参考https://github . com/UCSD-AI4H/COVID-CT/blob/master/COVID-CT-dataset . pdf
科维德-CXR:一个开源的可解释的深度 CNN 模型,用于预测胸部 X 射线中新冠肺炎的存在

图 1:解释二元模型对测试集中的一个新冠肺炎例子的预测的例子。有助于(绿色)和反对(红色)新冠肺炎预测的彩色区域。
编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
乔维德-CXR
为了对新冠肺炎疫情的全球反应做出贡献,我和 Blake VanBerlo 正在发布一个开源的可解释的机器学习模型【covid-cxr,它成功地从胸部 x 光片中预测了新冠肺炎的存在。这项工作来自加拿大伦敦市的人工智能研究和创新实验室。这是一个原型模型,还不是一个诊断工具。它建立了一个基础,如果有更多的数据和临床专业知识,这种模式可能会对全球抗击新冠肺炎产生重大影响,特别是在世界上的农村地区,x 射线比当前使用 RT-PCR 的检测试剂盒基础设施更容易获得,周转更快。
COVID-CXR 是一种深度卷积神经网络,允许二进制和多类分类。对大约 1000 个新冠肺炎阴性和 76 个新冠肺炎阳性的胸部 x 光片训练二元分类器。我们小心翼翼地加入更多新冠肺炎的负面形象,担心会造成太大的阶级不平衡。给定这个相对较小的训练数据集,我们在测试集上实现了令人鼓舞的模型指标,AUC 为 0.9633,灵敏度或召回率为 0.875。要更深入地了解这个模型,请查看我的同事布莱克的文章。

图 2:深度 CNN 模型架构
我们已经注意到上周其他一些研究人员也在探索这个问题,但他们的建议有重大缺陷: a) 他们缺乏可解释的人工智能,使模型能够解释其预测。这对于在医疗保健环境中建立临床医生的信任,以及确保该模型不拾取无意义的相关性是必不可少的; b) 它们只是学术探索,其代码的可扩展性有限,因此限制了医疗保健机构快速构建模型并在临床环境中将某些东西投入生产的能力;或者 c) 利用了多个数据集,这些数据集以这样或那样的方式向模型泄露了基本事实,并导致了错误的高模型度量。这个库通过可解释、可扩展和良好的测试减轻了这些问题。我们还试图确保它是模块化的,并有良好的文档记录,以提高临床医生和数据科学家构建和贡献模型的速度。未来几周,我们将继续向模型库添加功能。
COVID-CXR 的未来发展
我们对该模型的后续步骤包括:
- 使用资源充足的云计算基础设施进行详尽的模型架构超参数搜索,以找到不受计算机 GPU 限制的最佳模型。
- 在放射科医师的帮助下继续改进模型的解释,以进行特征工程和其他模型改进(目前使用局部可解释的模型不可知解释,时间)。
- 通过执行医疗从业者与伦敦市之间的数据共享协议,与医疗从业者合作,整合更多数据以支持改进模型指标。
呼吁合作
我们邀请所有数据科学和医疗保健从业者与我们合作。如上所述,这个模型是一个原型,我们需要更多的数据和更多的临床专业知识来扩大这个模型。如果您对合作感兴趣,请通过以下信息联系我们:
马特·罗斯,
人工智能经理,
信息技术服务,
城市经理办公室,
伦敦金融城公司
maross@london.ca
资源:
编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
Covid Data Science 推出预测和概率引擎
为新冠肺炎建立一个工作预报模式
由于新冠肺炎继续在世界各地造成破坏和疾病,我们决定创建一个工具,将人口与最近的病例结合起来,预测被感染的概率。这一工具现在可供公众和政府机构成员使用。

该数据适用于美国所有县、州和许多国家的省。这段视频深入探讨了这一主题,但我们只是用 7 天的时间创建了一个日平均值,然后用总体来计算概率。我们还应用了一些特殊的逻辑规则来帮助我们处理数据馈送中令人头疼的问题,比如空值和国家值在只能上升的时候下降。
我们还开发了一个 ARIMA 模型,在这个模型中,您可以向前移动时间(最多 10 天)来查看病例将如何增加。该模型使用过去 7 天和预计衰变率来尽可能准确地预测病例数。
我们的分析部分有一个每日指数增长图,这非常有利于了解增长何时放缓,但可能至少在未来 7-14 天内还不会显示在每日案例中。我们还有一个图表,可以让你选择任何地点的组合,并根据进入疫情的天数进行比较,这样更容易看到不同国家的反应。

Covid 数据科学可以访问这里。
Covid 数据科学由数据科学家、程序员和机器学习专家组成。
用非常简单的逻辑回归检测假新闻

图片来源:Unsplash
自然语言处理,NLP,Scikit Learn
这一次,我们将使用我不久前收集的数据,创建一个简单的逻辑回归模型来将 COVID 新闻分类为真或假。
这个过程出奇的简单和容易。我们将清理和预处理文本数据,使用 NLTK 库执行特征提取,使用 Scikit-Learn 库构建和部署逻辑回归分类器,并在最后评估模型的准确性。
数据
数据集包含 586 条真新闻和 578 条假新闻,几乎对半分割。因为数据收集偏差,我决定不使用“源”作为特征之一,而是将“标题”和“文本”合并为一个特征“标题 _ 文本”。
fake_news_logreg_start.py

预处理
让我们来看一个标题文字组合的例子:
df['title_text'][50]

看看上面的标题和文本的例子,它们非常干净,一个简单的文本预处理就可以了。因此,我们将剥离任何 html 标签,标点符号,并使他们小写。
fake _ news _ logreg _ 预处理. py

下面的代码将标记化和词干化技术结合在一起,然后在“title_text”上应用这些技术。
porter = PorterStemmer()def tokenizer_porter(text):
return [porter.stem(word) for word in text.split()]
TF-IDF
这里,我们将“标题 _ 文本”特征转换成 TF-IDF 向量。
- 因为我们之前已经将“title_text”转换为小写,所以这里我们设置了
lowercase=False。 - 因为我们已经注意到并对“title_text”应用了预处理,所以这里我们设置了
preprocessor=None。 - 我们用之前定义的标记化和词干化的组合来覆盖字符串标记化步骤。
- 设置
use_idf=True启用逆文档频率重新加权。 - 设置
smooth_idf=True以避免零分割。
fake_news_logreg_tfidf.py
文献分类的逻辑回归
- 我们可以使用一个估计器
LogisticRegressionCV,而不是手动调整 C 参数。 - 我们指定交叉验证折叠的数量
cv=5来调整这个超参数。 - 型号的度量是分类的
accuracy。 - 通过设置
n_jobs=-1,我们将所有的 CPU 内核专用于解决问题。 - 我们最大化优化算法的迭代次数。
- 我们使用
pickle来保存模型。
false _ news _ log reg _ model . py
模型评估
- 使用
pickle加载我们保存的模型。 - 使用该模型查看以前从未见过的数据的准确性得分。
fake_news_logreg_eva.py

Jupyter 笔记本可以在 Github 上找到。享受这周剩下的时光。
COVID19 —西班牙和意大利的情况是否特别危急?
COVID19 上的信息图形和统计数据
本文通过一些信息图表和统计数据显示了意大利和西班牙的死亡率比率和严重病例数的异常情况。在这两个国家,与报告的严重病例数量相比,死亡人数过多。这怎么解释?

(数据来源:https://www . world ometers . info,图文: www.stoeckl.ai )
COVID19 病毒的危险已经并仍在被大量谈论和报道。一方面,他们试图从统计数据中得出结论,另一方面,媒体和私人接触中的报道描述了个人的情况和戏剧性。所以每个人都已经熟悉了一些报道,例如,一位意大利医生被指控。但在私人领域,经验的报告也在积累,这与仍在流传的那种“只是另一场流感”的报告相矛盾。因此,以下统计数据不应被用来淡化这种情况。
作为一名统计学家,我想回答一些关于国家间死亡率和重症比例差异的问题。
作为数据源我使用:
https://www.worldometers.info/coronavirus/
许多国家的数据是否是最新的:
- 病例数、严重病例、当前病例
- 新病例数
- 死亡人数和新增死亡人数
- 康复人数
- 每百万人口的病例和死亡率
(评价时间:26.3。14:30)
对于有许多病例的国家,下面的柱状图显示了报告为严重病例的百分比。条形图的颜色表示该国迄今为止的病例数,颜色越深,病例越多。

(数据来源:https://www . world ometers . info,图文: www.stoeckl.ai )
当然,像法国这样的国家(超过 11%的病例被列为严重)和像德国这样的国家(只有 0.06%)之间的巨大差异是惊人的。
这些差异从何而来?
死亡率差异的问题已经在报刊和文章中得到广泛讨论。媒体文章比较了意大利和韩国的情况。分析的重点是各国年龄结构和患者年龄结构的差异。
一项科学研究的讨论涉及死亡率以及中国和意大利年龄结构的差异。
奥派出版社讨论了许多原因,就像这篇文章一样。典型的奥地利方式是,由于“Ischgl”中的热点和来自那里的传播,奥地利和在奥地利有滑雪游客的国家的低死亡率,可以归因于年轻健康滑雪者的大比例。
瑞士出版社 论述了两个因素,一方面是年龄结构的差异,另一方面是医疗保健制度。
德媒 发挥作用的不仅有年龄结构和医疗保健体系还有各国不同的检测方法。
正如我的柱状图所示,不仅各国之间的死亡率有很大差异,而且重症病例的比例也有很大差异。这可能与我刚才列举的原因相同。
但是重症比例和死亡率之间应该有明确的联系。如果有很多严重病例,应该会有很多人死亡。看文章开头包括回归线的散点图。
意大利和西班牙的数据不在本报告中所有其他国家的数据之内。与重症病例的比例相比,死亡率太高了。对于所考虑的所有其他国家,这些点或多或少位于一条直线上(线性关系)。
这只能用意大利和西班牙较差的医疗体系来解释吗?或者这是否表明这两个国家的情况非常危急,以至于重病患者无法得到足够的治疗?
最后,来看看一张世界地图上的危重病例比例分布。

(数据来源:https://www . world ometers . info,图文: www.stoeckl.ai )
比例最高的重症病例(橙色)主要出现在欧洲。
COVID19:跟踪生长因子、每日新病例以及在哪里找到它们。(世界、澳大利亚、维多利亚)
TLDR:人们很容易迷失在 COVID19 的噪音中,哪些新闻是真的,哪些是假的,应该关注哪些统计数据。答案:增长因素、世卫组织,以及你的政府(如果你信任你的政府的话)。请访问本文末尾的链接。
认知状态:统计学学位?没有。流行病学学位?没有。写这篇文章时,我不够资格,也过于固执己见。(最后一次内容更新:2020 年 3 月 27 日)。(我之所以关注澳大利亚和维多利亚州的数据,是因为我目前在墨尔本工作。虽然我来自印度尼西亚,但我不太相信印尼的数据,无法从中做出任何分析。)
勘误表:为了表明我是多么不合格,我把 R0 误认为生长因子。

要跟踪 COVID19,需要注意哪些统计数据?照片由粘土堤在 Unsplash 上拍摄。(我真的很怀念总死亡人数只有 6 000 人的那一天)。
什么是生长因子?
生长因子,告诉你情况是变得更糟还是更好。增长因子=1 一般意味着我们已经走了一半,事情会变得更好。你可以停止恐慌,但要保持警惕。然而,增长因子并没有被大量发表,因为当数据真的很嘈杂时,很难推断出 R。我试过。
所以,让我们记录每天的新病例。问自己一个问题:它已经达到顶峰还是正在下降?记住,这个数据是有噪音的,所以不要根据几天的时间就妄下结论。我通常会说,我们需要等待一到两个星期才能下定论。
在哪里,怎么做?
对于世界的数据,我相信约翰·霍普斯金。他们并不完美,所以也不要完全相信。这是链接:【https://coronavirus.jhu.edu/map.html】T4
约翰霍普金斯大学全球公共卫生、传染病和应急准备方面的专家一直在…
coronavirus.jhu.edu](https://coronavirus.jhu.edu/map.html)
转至右下方,点击如下图所示的“每日增加”。


https://www.reddit.com/r/uselessredcircle/

这是 2020 年 3 月 27 日的数据。还在涨,不好。(记住,无论今天推出什么样的社交距离政策,其影响都只能在两周内看到。此外,无论这里展示的是什么,都是两周前世界正在做的事情的影响。)
澳大利亚
向下滚动一点,你会发现:

每日新例是轴在左边的浅蓝色条形图。
好消息是,截至 2020 年 3 月 27 日上午 6:30,增长因子<1 for 3 days straight. Which means that the bar chart is steadily going down. Definitely too early to celebrate. But if this trends continues, the worse has come to pass. 假设这一趋势持续,峰值约为 2 000 例。因此,估计总数大约是这个数字的两倍,即 4 000 宗。澳洲有 90 000 张病床,有 2000 台呼吸机,只有 19%表现出严重或更严重的症状(基于中国数据)。2 000 x 19% = 380 名严重或更严重的患者> 2 000 台可用呼吸机(尽管我们现有的患者已经因为非 COVID19 原因使用呼吸机)。所以看起来这是可以控制的。但是这只有在人们保持社交距离的情况下才是真的!人能做的最愚蠢的事情就是看着数据,把它曲解为事情已经结束,放松自己的社交距离,把之前的所有努力都付诸东流。
(也许在不久的将来(几周),政府可能会稍微放松社会距离,非常精确地控制即将到来的第二波,以可控的方式慢慢建立群体免疫。但是让我们把所有的决定都交给专家吧。)
维多利亚
[## 电源 BI 报告
由 Power BI 支持的报告
app.powerbi.com](https://app.powerbi.com/view?r=eyJrIjoiODBmMmE3NWQtZWNlNC00OWRkLTk1NjYtMjM2YTY1MjI2NzdjIiwidCI6ImMwZTA2MDFmLTBmYWMtNDQ5Yy05Yzg4LWExMDRjNGViOWYyOCJ9) 
每日新例是左边有轴的深蓝色条形图。
真的慢下来了吗?真的很难讲。

真的慢下来了吗?
有三次,我们的增长因子连续两三天小于 0,但第二天就飙升,达到一个新的高度,比以往任何时候都糟糕。这就是为什么我们必须等待一到两周才能得出任何结论,也不要对澳大利亚的数据过于乐观。
参考文献和致谢
所有图片均基于以下来源(除非另有说明。):
- 世界(约翰·霍普斯金):https://coronavirus.jhu.edu/map.html
- 澳洲(卫生署):https://www . health . gov . au/news/health-alerts/novel-coronavirus-2019-ncov-health-alert/coronavirus-新冠肺炎-current-situation-and-case-numbers
- 维多利亚(卫生部):【https://app.powerbi.com/view? r = eyjrijoiodbmmme 3 nwqtzwnlnc 00 owrkltk 1 njytmjm 2 yty 1 mji 2 nzdjiiiwidci 6 immwzta 2 mdfmlmtbmywmtndq 5 YY 05 yzg 4 lwex MDR jngviowyyocj 9
谷歌云平台上意大利案例的新冠肺炎公共数据集
在 BigQuery 和 Datastore 上公开提供来自真实患者病例的医疗记录和实体!
当医疗专业人员正在拯救世界的时候,我想到了我们这些数据科学家如何尽我们的一份力量来帮助解决新冠肺炎全球疫情问题(当然,除了呆在家里)。

像每一个自尊的数据科学家一样,在我信任的数据中。就在那时,我开始寻找新冠肺炎数据集,并偶然发现了意大利医学和介入放射学协会的网站。
除了拯救世界,他们还抽出时间定期更新网站,更新他们治疗的新冠肺炎病例的最新医学记录和医学图像的 pdf 文件。太棒了。
希望这个数据集将帮助研究人员和其他贡献者对抗冠状病毒全球疫情。潜在的应用包括但不限于:
-知识图表(例如揭示隐藏的模式……)
-Q&A 系统(例如实时 FAQ)或聊天机器人(例如规模客户服务)
-等等!!
那是旅程开始的地方。

谷歌云管道架构
到本文结束时,您将得到 2 个数据集 :
1 个。big query 上的表包含意大利语(基本事实)、英语和策划英语的非结构化文本。
2。No-SQL 数据库,包含来自精选英语文本的分类医疗实体。
您将在本报告中找到所有细节,以重现相同的数据集,并做出您想要的更改,从而最大限度地满足您的需求。
一.数据提取
起点是一个带有医疗记录和图像的 pdf 文档。以下是提取数据的步骤:
- 从 ISMIR 网站下载 pdf 文件(手动流程)
- 将每个案例的页面分开(手动流程)
- 使用 Google Cloud Vision API 提取文本— DOCUMENT_TEXT_DETECTION。
从 Vision API 解析 json 输出的函数
二。数据处理
不幸的是,医疗记录是意大利语的。以下是处理原始文本的步骤:
- 使用谷歌翻译 API 将意大利语翻译成英语
调用谷歌云翻译 API 的函数—批处理模式
2.管理文本:管理包括使用正则表达式删除文本(例如日期、图片标题…),删除自定义停用词等等…我发现这篇来自 KDnuggets 的文章非常有帮助。
3.从 Scispacy 中提取 UMLS 医疗实体,使用模型“用更大的词汇量和 60 万字向量对生物医学数据进行训练”。
函数从文本中提取医疗实体
三。数据存储
- 将原创和策划的文本上传到 BigQuery (repo 可以在这里找到)。该表包含 3 种格式的医疗记录的基本事实: raw_it_text 、 eng_raw_txt 和 eng_txt (策划版本)。
包含所有提取文本的 FBQ 数据集
以下是查询公共 BigQuery 数据集的代码片段:
查询公共 BQ 数据库的 Python 示例代码
2.将每个病例的 UMLS 医疗实体上传至数据存储库(可在此处找到回购)
包含所有医疗实体的数据存储数据集
四。现在怎么办?
在这次旅程中,我直接从医生的笔记中了解了许多关于 COVID19 的知识。我注意到文本管理还远远不是最佳的。有大量的“垃圾”通过裂缝,并被错误地挑选为医学实体。
有趣的是,我发现“疾病或综合征”这个实体非常有启发性。事实上,它强调了病人表现出的所有症状(也称为共病)。正如所料,你会发现许多与呼吸衰竭症状相关的实体(如双侧间质性肺炎……)。然而,非常有趣的是,我们注意到许多病例也显示了心脏病相关实体(例如心包积液……)。
我也有责任敦促打算使用这个数据集的人在发表早期结论之前注意偏差(样本偏差、社会偏差、确认偏差和其他……)。
改进:
- 在当前管道中,必须在上传所有感兴趣的文档后手动触发管道(批处理模式)。管道的下一个版本将包括云函数,一旦一个新的文档被放入桶中
(即将推出…) - 使用数据丢失防护(DLP) API 对数据进行去识别。基于医疗机构 ISMIR 公开发布 pdf 的假设,此管道的第一个版本不包括删除 PII 信息的步骤。管道的下一个版本正在开发中,将包含这一特性。
(即将推出…) - 我绝不是自然语言处理方面的专家,相反,我相信,通过更有意义的处理,英语文本的整理可以得到显著改善(如果你有任何建议,请随时贡献)。
就这样结束了!
希望这篇文章戳中你的好奇心!如果你有什么改进的建议,请告诉我。此外,请分享您对 Google Cloud 面临的任何问题的反馈或意见。
我希望听到任何能够利用这个数据集和/或代码的人的意见。对您正在进行的工作发表评论。
COVID19:策划的 7 大在线互动模拟。
TLDR:交互式模拟是直观了解复杂系统的好方法。没有比流行病学更复杂的了。这里是我发现的一些最好的新冠肺炎流行病学在线互动模拟。
认知状态:没有流行病学资格,也没有模拟。只是一个偶然的模拟爱好者。这使我不够资格和过于固执己见。请注意,这些模拟只是为了寓教于乐。对现实世界中的任何事情,比如决定金融战略、公共卫生政策,或者诸如此类的事情,都不是。真正的交易要比这复杂得多。
编者注: 走向数据科学 是一份以研究数据科学和机器学习为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。

我在 Unsplash 上搜索“模拟”时发现了什么。科学高清照片在 Unsplash 上
有很多方法可以对个体进行建模(台球 vs 像素),甚至是是否首先对个体进行建模(PDE)。因此,这将按类别分组,没有特定的顺序(实际上,从我认为最直观的理解):
《华盛顿邮报》的#1 台球: 这些模拟显示了如何使冠状病毒的增长曲线变平

WaPo 的台球模型截图。
华盛顿邮报使用了一个台球模型,其中每个人都是一个完全弹性的 2D 圆,以恒定的速度在一条直线上,生活在一个具有完全弹性的墙壁的矩形中。这是提出球形牛的一个非常好的时机:

球形奶牛。来源:http://www.cs.cmu.edu/~kmcrane/Projects/ModelRepository/
一个牛奶场的牛奶产量很低,所以农场主写信给当地大学,向学术界寻求帮助。组建了一个由理论物理学家领导的多学科教授小组,并进行了为期两周的密集现场调查。然后,学者们回到大学,笔记本上塞满了数据,写报告的任务就交给了团队领导。此后不久,这位物理学家回到农场,对农民说,“我有解决办法,但它只适用于真空中的球形奶牛”。【http://www.physics.csbsju.edu/stats/WAPP2_cow.html
我不是在取笑阿婆。整个想法是,设计模拟是一门艺术。制作一个完美的世界模拟太难了。你需要在某个地方做一些假设和简化,不要把它做得太简单而失去我们想要模仿的行为。我认为 WaPo 做出了正确的决定。(如果需要更复杂的台球模拟,尽管不是交互式的,请查看最后荣誉奖部分的 3 blue 1 brown)https://www . Washington post . com/graphics/2020/world/corona-simulator/
警告健康:此图形需要 JavaScript。请启用 JavaScript 以获得最佳体验。请注意…
www.washingtonpost.com](https://www.washingtonpost.com/graphics/2020/world/corona-simulator/)
#2 台球由 Petr nio Silva:基于代理人的新冠肺炎健康和经济效果的模拟

另一个台球模型由Petr nio Silva在基于代理人的新冠肺炎健康和经济效应的模拟。
Petrô nio Silva 和他的团队制作了另一个台球模型,他们比较了 5 种不同的场景。这同时减少了互动也增加了互动。交互性较差,因为要与之交互,你需要了解 Python。然而,如果你这样做,它更具互动性,因为你可以疯狂地玩它。我也喜欢文章结尾的引用,以下是摘录:
所有的模型都是错的,但有些是有用的。(乔治·博克斯)
(对于更复杂的台球模拟,尽管不是交互式的,请查看最后荣誉奖部分的 3blue1brown)
以下是解释模拟“基于代理人的新冠肺炎健康和经济影响模拟”的文章:https://towards data science . com/Agent-Based-Simulation-of-the-新冠肺炎-健康和经济影响-6aa4ae0ff397
我们生活在一个不寻常的时代,人类受到一种微生物的攻击,威胁着我们的…
towardsdatascience.com](/agent-based-simulation-of-covid-19-health-and-economical-effects-6aa4ae0ff397)
而这里是代码:https://colab . research . Google . com/drive/1 xyrq 9 dsq 9 kjuxu 8 MF 6 by-D2 gjvzjquk
凯文·西姆勒在他的博客上写道: 爆发

爆发中最终模型截图。
凯文·西姆勒在他的博客上融化的沥青 : 爆发。他没有把人建模成台球,而是把它建模成网格中一个静止的正方形细胞。通过简单地成为邻居(共享边,而不是角落)来模拟具有传染潜力的互动。我会把这个叫做网格/点阵/细胞/像素/光栅/ 元胞自动机 / 康威的生命游戏 / 有限元法。最有趣的是,即使在提出一个完全不同的模型和假设时,它也会得出与台球模型相似的结论。
有很多参数可以使用,但不要太多。而且整篇博文的作用就像一个教程,一个一个的给你介绍参数(读作:游戏力学)。下面是链接:https://meltingasphalt.com/interactive/outbreak/
可播放的疾病模拟
meltingasphalt.com](https://meltingasphalt.com/interactive/outbreak/)
《华盛顿邮报》报道:像新冠肺炎这样的流行病如何终结(以及如何更快终结)

六边形网格模拟,通过 WaPo 比较不同的疾病。
与融化的沥青非常相似,互动少得多,但有一个关键的区别,六边形网格。虽然更容易编码,但是使用正方形网格会导致许多问题,比如它如何像菱形(如果你使用 4 个邻居)或正方形(如果你使用 8 个邻居)那样扩散。简而言之,六角形通常更适合模拟,因为它是可以平铺空间的最圆的形状。你可以在这里和这里阅读更多。

为什么十六进制比正方形好。https://pro . ArcGIS . com/en/pro-app/tool-reference/spatial-statistics/h-whyhexagons . htm
健康和警告:此图形需要 JavaScript。请启用 JavaScript 以获得最佳体验。作为…
www.washingtonpost.com](https://www.washingtonpost.com/graphics/2020/health/coronavirus-how-epidemics-spread-and-end/)
R2D3 的#5 网络:通过模拟理解 COVID19】

来自 r2d3 的第四次模拟截图。
R2D3 是一个优秀的网站。我知道它们,因为我教 机器学习并且它拥有可视化决策树和偏差-方差权衡的优秀资源。所以当我看到他们做新冠肺炎模拟,我必须去看看,我没有失望。
这是一个更有趣的模拟,因为网络是流行病学家会使用的实际结构,而不是台球或网格。“网络”的官方术语叫做图。但这不是指图表,外行人也称之为 graph。(如果我没看错的话,著名游戏瘟疫公司也使用 graph 作为底层模型)。这里是文章的链接:http://www.r2d3.us/covid-19/
2020 年 3 月 31 日关于 COVID19 的消息铺天盖地。病例激增,防止进一步传播的措施…
www.r2d3.us](http://www.r2d3.us/covid-19/)
Gabriel Goh 的#6 微分方程:流行病计算器

Gabriel Goh 的 SEIR 互动模拟截图。
到目前为止,所有的模拟都可以归入基于代理的模型,在这里我们在个体水平上模拟疾病。但这不是唯一的做事方式。我们可以在亚种群水平上实现。这就是先生(易感、传染、康复)模型正在努力做的事情。在 SIR 中,使用微分方程对亚群体之间的传播进行建模。(要了解更多关于 SIR model 的信息,请查看最后荣誉奖部分的 Numberphile 链接。)
请注意,SIR 是一个合法的成熟的学术水平模型。这里实现的是 SIR 的一个变种,叫做 SEIR(易感、暴露、感染、删除)。下面是链接:http://gabgoh.github.io/COVID/index.html
[## 流行病计算器
编辑描述
gabgoh.github.io](http://gabgoh.github.io/COVID/index.html)
艾莉森·希尔的 7 号微分方程:模拟新冠肺炎传播与医疗保健能力

SEIR 模型截图艾莉森·希尔。
另一种实现 SEIR 模式为上述第二种意见。(要了解更多关于 SIR model 的信息,请查看最后荣誉奖部分的 Numberphile 链接。)下面是链接:https://alhill.shinyapps.io/COVID19seir/?FB clid = iwar 2 axjt 79 m2 amz xmdy 8 jsieusc 4 I 7 iju 8 av 6 ob 4 dmlziej 2v qgl 7 TT 3 qgxa
[## 模拟新冠肺炎传播与医疗保健能力
我们使用一个基于经典 SEIR 模型的分室流行病学模型来描述疾病的传播和临床传播
alhill.shinyapps.io](https://alhill.shinyapps.io/COVID19seir/?fbclid=IwAR2aXJT79M2AmZxMdy8jsiEuSC4i7ijU8Av6oB4dmlZIeJ2VQgL7Tt3QGxA)
#奖金
因为我在写这个之前没有做详尽的研究。
又一个 SIR 模型感谢 reddit 的/u/好奇-b 通知我:【https://covid19-scenarios.org/】T2
该工具使用数学模型,根据用户定义的参数模拟各种新冠肺炎结果
covid19-scenarios.org](https://covid19-scenarios.org/)
荣誉奖
这些相关的东西不是交互式的在线模型:
更复杂的台球由 3blue1brown: 模拟一场流行病
正如预期的那样, 3b1b 做出了惊人的模拟,新增了将人口划分为孤立的地理区域、城市中心、使用排斥力模拟社会距离等功能。不幸的是,它不是交互式的。反正下面是链接:https://www . 3 blue 1 brown . com/videos-blog/simulating-an-epidemia
图由 Ndemic 创作:瘟疫公司
这是我的胡乱猜测。但是我认为著名的游戏瘟疫公司使用基于图形的建模,就像上面提到的 R2D3。https://www.ndemiccreations.com/en/22-plague-inc
瘟疫公司是一个高战略和可怕的现实模拟的独特组合。你能感染世界吗?你的…
www.ndemiccreations.com](https://www.ndemiccreations.com/en/22-plague-inc)
数字爱好者理解 SIR 模型:冠状病毒曲线
其中两个模拟使用了基于 SIR 模型的 SIER 模型,并假设观众对它很熟悉。如果你不是数字迷,有很棒的视频解释这个模型能捕捉什么,不能捕捉什么。
FiveThirtyEight 对 SIER 模型的警告:为什么做一个好的新冠肺炎模型如此之难
后两种模式在另一方面有所不同。他们试图使用真实世界的数字。这有很多问题。这篇文章很好地总结了为什么很难很好地估计插入到这些模型中的实际数字,并且很好地概述了模型可以变得多复杂。以下是链接https://fivethirtyeight . com/features/why-it ' s so-freaking-hard-a-good-model/
我们在这里,在疫情的中间,像观赏鱼一样盯着我们起居室的窗户。关于…的问题
fivethirtyeight.com](https://fivethirtyeight.com/features/why-its-so-freaking-hard-to-make-a-good-covid-19-model/)
超越模型作者托马斯·普约:锤子与舞蹈
既然你已经内化了流行病的动态,当其他人谈论处理这种情况的策略时,你可以有更好的欣赏。这种策略的一个很好的例子就是这篇文章:https://medium . com/@ tomaspueyo/coronavirus-the-hammer-and-the-dance-be 9337092 b 56
如果领导人给我们争取时间,未来 18 个月会是什么样子
medium.com](https://medium.com/@tomaspueyo/coronavirus-the-hammer-and-the-dance-be9337092b56)
超越模型由我们的世界在数据:统计和研究
同样,随着更深入、更直观的理解,数据现在应该更有意义。这里有一个很好的详细的数据分析:https://ourworldindata.org/coronavirus
注意:为了让你自己了解和理解对公众的风险,我们建议依靠你的政府机构负责…
ourworldindata.org](https://ourworldindata.org/coronavirus)
无耻的自我推销
我也试着给新冠肺炎做模特。我以前的相关帖子:
- COVID19:跟踪生长因子、每日新病例以及在哪里找到它们。(世界,澳大利亚,维多利亚)
- 现实世界数据的杂乱:用 logistic 函数追踪 COVID19 的生长因子。
- 现实世界数据的混乱 2:比较国家间的增长因子。
参考文献和致谢
标题中提到了所有图片的来源。
每个来源的链接可在各自的标题上找到。
感谢 Phillip Luong 向我介绍 SIR model 和上面的一些链接。
COVID19:用 Python 可视化社交距离的影响
变更数据
使用 pandas 和 python 中的 matplotlib 可视化,一个人可以对平坦化曲线产生指数级影响。

拉平曲线
新冠肺炎接管了世界,并在短短几个月内让整个世界陷入停滞。世界上的总病例将很快达到 50 万,超过 20,000 例死亡已被确认。令人担忧的是,T2 的病例总数图仍在呈指数增长,而且没有放缓的迹象。
通过社交距离拉平曲线似乎是唯一的出路。在过去的几周里,许多国家都被封锁,人们被要求严格呆在家里。所有这些措施不会消灭病毒,但将有助于减缓它的传播,从而减轻卫生保健系统的压力,从而降低死亡率。
但是许多人似乎仍然不理解社交距离的严重性,以及即使是一个人也能产生多大的影响。关键是,如果你是一个健康的个体,病毒可能不会对你产生太大影响,但你可能会将它传播给其他可能受到它不利影响的人。
因此,在这篇简短的帖子中,我将尝试使用 python 来可视化社交距离的效果,以了解每个人在阻止新冠肺炎病毒传播方面可能产生的巨大影响,并有可能挽救成千上万人的生命。
实验
这项实验的目的不是模拟病毒的传播,而是理解社会距离在减少病毒传播方面的影响,并认识到它的重要性。
首先让我们导入要点并定义几个参数。
让我解释一下每个参数:
- 天数:这只是我们进行模拟的天数
- 人口:我们模拟城市的人口。
- SPREAD_FACTOR:是感染者接触的人数。在一个城市里,据说一个普通人一天至少要接触 16 个人。假设只有四分之一的人会被感染,我选择传播因子为 4。需要注意的是,扩散系数取决于许多变量,在现实生活中不会保持不变。
- 恢复天数:感染者恢复所需的天数。在现实生活中,这也不是一个常数,但 10 是一个很好的平均值。
- 最初受影响的人数:最初受病毒影响的人数。他们是携带者,把病毒从一个受感染的地区带到一个新的地区,就像我们假设的城市。
我们将使用一个数据框架来模拟一个城市,其中每行对应一个公民,并跟踪感染和康复的人。使用 sample 函数可以从数据框中随机选择人。我们将这样做:
- 创建一个名为 city 的数据框架,其中每一行对应于城市中的一个人。它还包含标记一个人何时被感染和康复的栏。最初随机选择最初受感染的人,使用样本并将他们标记为受感染。也纪念他们的康复日。
- 运行 for 循环天数来模拟过去的每一天。
- 查看这一天康复的人数,标记为康复。这些人不会再传播病毒了。
- 每天统计感染人数,使用 SPREAD_FACTOR 计算当天新感染的人数。所以一天的新增病例数= SPREAD_FACTOR *活跃病例数。
- 记录活动案例的数量和康复的人数,以便日后可视化。

输出
你可以看到,在大约 10 到 15 天内,整个 10 万人口都受到了影响并得到了恢复。这是假设这座城市能够同时治疗 10 万名患者,并且每个人都以相同的速度康复——10 天。但是你认为这个假设的 10 万人口的城市会有一个每天可以处理 10 万个活跃病例大约一周的医疗保健系统吗?现在在现实中,增长可能不会如此剧烈,但如果我们不采取任何行动,它很容易导致这样的事情。
现在让我们看一下 SPREAD_FACTOR 的不同值的图表。

观察结果:
- SPREAD_FACTOR = 1(左上):这意味着每个被感染的人都与一个随机的人接触过,这个人如果没有被感染,也已经被感染了。几乎所有的人口都受到了影响。
- SPREAD_FACTOR = 0.5(左下角):每两个感染者中,每天就有一个新感染者。请注意,这个新人的选择是随机进行的,只有在这个人没有被感染的情况下才会被感染。这里的曲线仍然与第一个案例几乎相同,但总病例数下降了约 20,000 例。
- SPREAD_FACTOR = 0.25(右上):每 4 个感染者,就有一个人被感染(如果还没有被感染)。或者换句话说,这 4 名感染者中有 1 人接触了新感染的人(其他 3 人在练习社交距离!).这可能是一种所有人都有意识地隔离自己、练习社交距离的状态。从之前的案例来看,仅仅通过将价差系数减半,价差就已经呈指数级下降,曲线也明显变平。这里的保健系统应该能够提供良好的护理,因为在高峰期,只有 40,000 个活跃的病例。
- SPREAD_FACTOR = 0.2(右下方):在这里,每 5 名感染者中就有一人与新的人接触并传播了感染。另外 4 人被隔离。与上一个案例没有太大的不同,但是曲线明显变平了,活动案例的峰值几乎下降了一半!
在最后两种情况下,你可以观察到一个人对整个病毒传播的影响!由此我们可以得出结论,尽管病毒呈指数传播,但社交距离也呈指数传播,每个孤立的人都会对曲线的平坦化产生指数影响!
注意:我知道这是对真实世界场景的过度简化,但我认为它让我们很好地理解了 SPREAD_FACTOR 和活动案例数之间的关系。此外,指数函数可以很容易地用数学方程模拟,但我认为这更直观,更容易理解。
好吧,现在你知道为什么社交距离如此重要了吧!基本上,你坐在家里就是在拯救生命。
你可以在这个谷歌实验室 找到 的代码。您可以尝试不同的参数值。另外,尝试可视化其他指标,如每日恢复率。您可以尝试在不同的时间间隔减少扩散因子,并观察其效果,而不是在整个模拟过程中保持扩散因子的恒定值。我注意到一旦伤害已经造成,就没有回头路了。
所以练习社交距离,洗洗手,记住,我们都在一起!
参考资料:
实时统计和冠状病毒新闻,跟踪确诊病例、康复患者和死亡人数,按…
www.worldometers.info](https://www.worldometers.info/coronavirus/) [## 冠状病毒:为什么你必须现在行动
政治家和商业领袖:你应该做什么,什么时候做?
medium.com](https://medium.com/@tomaspueyo/coronavirus-act-today-or-people-will-die-f4d3d9cd99ca) [## 这些模拟显示了如何使冠状病毒的增长曲线变平
警告健康:此图形需要 JavaScript。请启用 JavaScript 以获得最佳体验。请注意…
www.washingtonpost.com](https://www.washingtonpost.com/graphics/2020/world/corona-simulator/)
联系我!
adarsh1021@gmail.com
推特:https://twitter.com/adarsh_menon_
另外,如果你对机器学习感兴趣,可以看看我的 YouTube 频道!
编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
COVID19 语音助手
让我们听听这种病毒对我们世界的影响
冠状病毒已经在全球范围内造成了巨大的破坏。数百万人被感染,数千人死亡。疫情仍在上升,因为世界上所有国家都实行了封锁。每个人都有权知道这种病毒是如何影响我们的生活的,因为我们仍在继续与它作战。所以,我写了这篇关于我的项目的文章,用一种声音来表达世界的现状。

格伦·卡丽在 Unsplash 拍摄的照片
语音助手项目
在这个项目中,您将学习如何使用 Python 构建一个 COVID19 语音助手。该项目主要涵盖了 python 中网页抓取、语音辅助和多线程的基础知识。
网页抓取
该项目使用了一个名为 的工具。ParseHub 是免费的 web scraper,功能非常强大,并且易于使用。这个工具允许你仅仅通过点击你想从那个网站得到的元素来抓取网页。所以,第一步是下载 ParseHub 。
我们将从非常著名的统计网站 Worldometers 上搜集定期更新的冠状病毒信息。打开 ParseHub - >开始新项目- >粘贴链接到 worldometers。
单击您想要从页面中抓取的元素,并为它们分配唯一的标签。使用相关工具将页面上的“冠状病毒病例”与其编号联系起来。ParseHub 显然非常高效,它使用人工智能来理解您想要哪些元素。要尝试这种方法,将“美国”与“总病例数”联系起来,列表中的其他国家就会显示出来。太神奇了!这在幕后所做的是为上面链接的内容构建一个 JSON 格式。
完成链接后,点击“获取数据”,这可能需要一段时间。然后确保在下一个屏幕上记下 API 密钥、项目令牌和运行令牌。
语音助手
复制粘贴 Part1.py 中给出的代码,我会带你了解到底发生了什么。
以下几点解释了 Part1.py 文件:
- 这部分项目的需求是以下 python 包: requests , json , pyttsx3 ,speecher recognition, re 。因此,pip 安装了所有这些包。
- 在各自的变量中使用 API 密钥、项目令牌和运行令牌。
- 类数据有以下方法:
- get_data() :使用您最近在他们的服务器上运行的项目从 parsehub 获取数据,并将其返回。
- get_total_cases() :获取新冠肺炎在全球的总病例数。
- get_country_deaths() :获取全球新冠肺炎死亡总人数。
- get_country_data() :获取任何特定国家的新冠肺炎病例和死亡人数。
- get_list_of_countries() :获取所有国家的列表。
- speak() 方法初始化 pyttsx3 引擎,说出作为参数传递给它的文本。
- get_audio() 方法使用 google 的 recognize_google() 方法监听用户通过麦克风输入的语音,并返回输入的文本。
- 最后,main()函数负责使用正则表达式模式识别输入语音,并将它们分类为世界上的病例和死亡或任何国家的病例和死亡的模式。
- 匹配的模式调用特定的函数并大声说出数字。
多线程
到目前为止,您的助手只说出您最初获取的数据。保持数据更新是很重要的,因为这个全球疫情仍在进行,当你的助手说数字正在下降时,这将是令人欣慰的。
删除 Part1.py 并将 Part2.py 复制到您的应用程序中。
除了 Part1.py 之外,Part2.py 还有一个额外的函数和一个处理程序。这个函数就是 update() 函数。该函数不从 parsehub 上的最后一次运行中获取数据,而是在 parsehub 服务器上为您的项目初始化一次新的运行。这将需要一段时间,所以请在更新时给它一些时间。
最有趣的部分是减少这个时间。因此,我们使用 python 中的多线程库来利用多线程。通过这样做,我们可以确保语音助手在一个线程上运行,而数据更新在另一个线程上并行进行。
结果
这个项目最有趣的部分是它的结果。
运行 Part2.py 文件,当控制台显示“Listening…”时,说“number of total cases ”,助手将回复全世界的 COVID19 病例数。现在说,“印度总死亡人数”,助手会回复这个数字。
您可以说,“更新”,助手将为您更新这些值,这可能需要一些时间。请耐心等待。
你必须说“停止”才能退出正在运行的应用程序。
😲耶!!!你做到了!你刚刚建立了一个语音助手,只需使用你的声音就可以更新关于冠状病毒的信息。你可以进一步把这个项目发展成惊人的东西。要获得完整的见解,请查看我的 GitHub。
如果你有任何错误,请随时通过我的 LinkedIn 联系我。
希望你喜欢并理解这个项目。
谢谢你。
你住在哪里很重要!—基于 RShiny 和传单的可视化工具
美国各地的 COVID 差异

COVIDMINDER
在过去的一个月里,我一直在积极地与我的研究团队合作,探索 COVID 周围的数据,并开发一个可视化工具来了解美国各地的差异。我们最近发布了应用程序 COVIDMINDER 的第一次迭代,其中包括美国各地死亡率、测试病例、糖尿病和医院床位的差异,特别关注纽约。
在本帖中,我们将详细探究各种选项卡,并了解应用程序是如何设计的。此外,应用程序在不断发展,如果您在更晚的时间点阅读本文,您可能会看到更多的功能和选项卡。作为快速参考,这个应用是实时的:https://covidminder.idea.rpi.edu/,你可以继续探索 GitHub 上的代码:https://github.com/TheRensselaerIDEA/COVIDMINDER
这个想法
COVIDMINDER 是一个揭示结果、决定因素和药物的地区差异的应用程序。它探索有关新冠肺炎的数据,并试图提取和传播有关各种因素的信息。

差异指数
到目前为止,你一定遇到过一些仪表板,它们的基本概念是显示当前的统计数据、死亡病例数、总阳性计数等。在一个漂亮的界面中。
但是我们想做一些不同的事情。我们希望我们的仪表板不仅仅是直接输出数字。因此,我们决定扩大我们的数据范围,纳入可能与死亡率相关的因素。我们决定不仅包括死亡率,还包括每个州的医院床位、当前测试病例的数量以及糖尿病在全国的传播情况。此外,在这些因素中,我们计算了与该州人口相关的差异指数,以提供更好的可视化能力。
此外,我们决定将纽约纳入我们的分析,因为它不仅是目前最令人担忧的州,而且我也不在纽约,所以我可以亲眼目睹一切。
r-闪亮和传单

应用主页
你看到的应用程序是使用 R Shiny 从头设计的,这是一个 R 包,允许你使用 R 代码、HTML、CSS 和 Javascript 开发网站。我们探索了各种设计风格、布局和配色方案,最终选择了我们在图片中看到的那个。图中的颜色与背景形成强烈对比,以便更好地突出它们。
所有的情节(线情节除外),都是用传单包设计的。由于我非常熟悉传单图是如何制作的,我可以说地图设计非常直观,并且使得使用 geo 图非常简单。
情节
地理图

使用传单的地理图
对于每个选项卡,我们决定在美国或纽约州的地理地图上绘制数据。各个州/县基于视差指数值进行颜色编码,范围从深蓝色到深红色。正如我前面提到的,我们用传单来产生这些情节。
您可以将鼠标悬停在任何州/县上,查看该地区的更多统计数据。每个悬停信息根据您所在的选项卡和差异指数而变化。
这些图是交互式的,允许你放大和缩小每个图。图例已添加到右下角。
线形图

纽约测试用例折线图
我们的申请中包含的第二种情节是自 3 月以来发生的纽约 COVID 案件。不出所料,纽约州作为一个整体是最高的。此外,紧随其后的是纽约,它实际上是迄今为止病例最多的县。
您可以通过选择边界框来放大和缩小图像,并更深入地探索绘图。各县的颜色基于下面定义的颜色图:

纽约地区的颜色编码
数学
差异指数用于描述一个州或县的相对位置。我们使用log值来标识索引。例如,为了计算美国各州死亡率的差异指数,我们使用以下公式
index = log(Mortality rate in state/Mean mortality rate in US)
韩国能够使用测试“拉平曲线”,因此,我们将我们的测试案例与韩国的比率进行比较。意大利的医院床位数较高,但仍无法满足所有需求,因此,我们将医院床位数与意大利的最低比率进行比较。
结论
开发这个应用程序让我们了解了很多关于 COVID 的情况,以及我们如何使用 R Shiny 和 Leaflet 等容易获得的工具来生成漂亮的可视化效果,使理解信息变得更加容易。
继续尝试 COVIDMINDER 应用程序,并与我们分享您的想法、想法和建议。
你可以通过网站上的评论表格联系我们,或者通过 LinkedIn 联系我:https://www.linkedin.com/in/bhanotkaran22/
Python 生成器是如何工作的?
CPython 解释器的内部

在本文中,我将试图提供对 Python 生成器的深入理解,以及它们如何从内部操作。它将包括如何和为什么。部分将是独立的,你可以随意跳过。事不宜迟,让我们开始我们的旅程。⛵️
什么是发电机?
从 Python 2.2 开始添加,生成器是可以暂停、恢复和迭代的独特函数。让我们看一个例子:
通过定义包含yield关键字的函数,该函数被标记为生成器。然后,我们按以下顺序运行生成器:
- 初始化发生器并将其放入
g。此时,我们有了一个尚未运行的新生成器对象。 - 通过呼叫
next()推进发电机。这导致生成器前进到第一个yield关键字,在途中打印“Hello”。 - 再次推进发电机。它打印“Goodbye ”,由于它到达了函数的末尾,它引发了一个
StopIteration异常并结束。
为了理解这三个简单的步骤,我们首先需要从 Python 中一个函数如何运行的基础开始。
函数如何工作
运行一个函数包括两个主要步骤:初始化和求值。

Jukan Tateisi 在 Unsplash 上拍摄的照片
初始化功能
在幕后,CPython 在一个框架对象中运行一个函数。
一个帧对象,有时称为堆栈帧,由以下字段组成:
- 代码对象 ,包含函数实际编译的代码。
- 释放堆栈空间 ,称为 value-stack ,用于运行解释器。
- 执行指针 为当前正在执行的代码行。
- 其他领域,如局部变量的映射。
所有帧场的列表可以在代码中看到,而更短的列表可以在文档中看到。
当我们初始化一个函数时,一个帧被创建。在伪代码中:
f = Frame()
我们传递给函数的参数然后在框架内被赋值为:
f.f_locals["arg1"] = arg1
f.f_locals["arg2"] = arg2
帧的执行点被设置为函数中的第一行代码:
f.lasti = 0 # Last Instruction
f.lineno = 0 # Function line number on file
此时,我们的函数开始运行。
运行功能
几乎整个 Python 解释器可以概括为一个 C 级函数:pye val _ eval frameex。
这个函数就是解释器循环。由 3k 行代码组成,它的工作是评估一个帧,或者换句话说,运行它。Python 中的每个函数,解释器运行的每个字节码或操作码,都要经过那个函数。
在“PyEval”期间,Python 对帧的唯一值栈进行操作。这条信息以后会很重要。
总之,当你输入一个函数,并运行它,解释器创建一个帧,并进入解释器循环。
一个叫做 PythonTutor 的网站有一个非常好的关于这种机制的交互例子。

PythonTutor 的例子截图
发电机如何工作
与函数非常相似,运行一个生成器包括初始化步骤和评估步骤。
初始化发电机
在这一步,我们正在创建生成器对象。生成器对象由帧对象和代码对象组成。如果你想知道,是的,框架对象中也包含代码对象。在伪代码中:
g = Generator()
f = Frame() # Initialized as before
g.gi_frame = f
g.gi_code = f.f_code = Code() # The compiled function
此时,我们的发电机g已经准备好运行。
推进(运行)发电机
每次我们调用next(g)时,都会使用同一个pye val _ eval frameex对帧进行求值。
不同的是,在运行生成器时,我们可以到达yield关键字,此时帧评估停止,生成器“暂停”。
保存帧中的指针,标记我们当前的堆栈位置,以便准确地知道停止时发生器的状态。
重要的是要记住,与函数不同,当求值停止时框架不会被破坏,因为它仍然连接到生成器对象。这将允许我们稍后加载它。
PyEval 返回,我们的调用函数恢复。
再次推进发电机
当我们再次推进发生器时,帧从gi_frame加载,PyEval 在相同的帧上再次被调用。它检查我们停止的地方,转到我们的执行指针,并使用存储在帧中的值堆栈。
因为我们使用的是同一个堆栈,而且这个框架也包含了所有的局部变量,我们可以从完全相同的地方继续,就好像函数从来没有停止过一样。
当我们到达生成器或返回语句的末尾时,StopIteration 被抛出,该帧被删除。gi_frame 然后将设置为None。
发电机特征

米克·豪普特在 Unsplash 上拍摄的照片
现在我们已经知道了生成器内部是如何暂停和恢复的,让我们深入了解一些使生成器真正不同凡响的特性。
产生价值
生成器可以产生值,允许它们被迭代并以一种懒惰的方式返回结果。例如:
在内部,产生值非常类似于获得函数的结果。当 PyEval 到达操作码YIELD_VALUE时,弹出栈顶值并返回。很简单,不是吗?
从发电机返回
生成器可以使用return关键字返回一个结果:
如您所见,return 语句设置了StopIteration异常。异常可以有参数,这里,发送给StopIteration异常的第一个参数是返回值。
可以通过捕获异常并获取其第一个参数来检索返回值:
与发电机通信
我们还可以使用[.send()](https://docs.python.org/3/reference/expressions.html#generator.send)和[.throw()](https://docs.python.org/3/reference/expressions.html#generator.throw)与发电机通信:
如您所见,我们使用.send()向生成器发送数字,它们是yield关键字的返回值。
在内部,.send()的工作方式是将值放在生成器堆栈的顶部。然后它评估帧,弹出栈顶值,把它放入我们的局部变量。
类似地,.throw()通过向 PyEval 发送一个[throwflag](https://github.com/python/cpython/blob/25104949a5a60ff86c10691e184ce2ecb500159b/Python/ceval.c#L1315)来说明发生了异常。然后,它正常处理异常。如果生成器没有捕捉到它,异常就会像普通函数一样向外传播。
嵌套生成器
可以使用关键字yield from嵌套生成器(或"委托"):
正如你所看到的,使用yield from创建了一种在最里面的发生器之间通信的方式,一直到外面。
在内部,它通过使用生成器对象的gi_yieldfrom字段来工作。它指向内部发生器,当你使用.send()时它会一直进去。
当内部生成器返回时,它沿着链向上,并相应地设置yield from的返回值。
结论
在本文中,我对 CPython 生成器实现的内部工作方式提供了一些见解。虽然这篇文章不是初学者的材料,但它只是触及了这个主题的表面,要理解解释器是如何工作的还有很多。完整的实现当然是开源的,欢迎大家随意探索。享受😉
地理空间分析破解选址难题(上)
基于开源工具和数据的端到端地理空间应用

图 1 槟城所有类型建筑的局部视图
选址是咨询行业的一个热门话题。在这篇博客中,我将介绍一个由开源 OpenStreetMap 数据集和 QGIS 支持的新颖解决方案。希望本案例研究能给从事选址相关项目的分析师和顾问带来一些新的思路。
问题陈述
假设我们有一个客户,他是一家连锁超市。他们计划在一个新城市开设零售店,比如马来西亚的槟城。为了实现利润最大化,他们需要决定要建多少分店以及应该建在哪里。如果我们试图从预测建模的角度开发解决方案,这将成为一个复杂的问题。利润似乎是一个合适的预测目标变量。然而,确定要使用的特性和编译特性集需要付出巨大的努力。
我提出的策略可以用一句话来概括:“找出客户密度较高、竞争对手较少的地点”。有了这个想法,这个问题可以通过以下三个步骤来解决。
1。模拟客户在整个城市的地理分布。
2。获取城市中潜在竞争对手的地理位置,包括任何其他连锁超市和杂货店。
3。根据不同地区的供需缺口,提出网点的位置。
本博客将重点介绍第一部分:客户分布模拟。
- 输入数据:槟榔屿市建筑物的 OpenStreetMap 形状文件,按地区分布的估计槟榔屿人口。
- 使用的工具:Python 3、QGIS(量子地理信息系统)3.4
数据源
让我们先来看看我们将要处理的数据。OpenStreetMap (OSM)是一个合作项目,旨在创建一个开源的可编辑世界地图。数据集包含各种类型的基础设施的形状文件,例如目标区域中的建筑物、道路、铁路。数据集每隔几小时更新一次。为了获得槟城的 OSM 数据集,我从 OSM 网站下载了马来西亚、新加坡和文莱的 shape 文件包。有几个 Python 库可以用来用处理形状文件。shp 后缀:菲奥娜, PyShp ,身材匀称, GeoPandas 等。在这项工作中,PyShp 用于将 shapefile 读入 dataframe。
osm_preprocessor.py

图 2 形状文件读取为熊猫数据帧
我想强调的一个有趣的特性是坐标,它以顺时针方向给出了建筑物顶点的纬度和经度。它可以用来估计建筑物的具体位置以及它们的占地面积。
另一个正在使用的数据是由槟榔屿研究所提供的按地区分布的估计槟榔屿人口。
估计 _ 槟城 _ 人口 _ 按 _ 地区 _2018.csv
地理上,槟榔屿市被槟榔屿海峡分为槟榔屿岛和槟榔屿。槟榔屿的五个区可以在下面的地图中看到。
来自维基共享,自由媒体仓库
commons.wikimedia.org](https://commons.wikimedia.org/wiki/File:Districts_of_Penang.jpg)
模拟方法和假设
在我们深入实施之前,这里我们有一个方法的概述。可以在以下步骤中模拟客户分布。
- 估计所有住宅建筑的中心地理编码和建筑面积(Python)。
- 将槟城分割成 1km x 1km 的网格,分别标注属于哪个区(QGIS)。
- 根据建筑物的中心地理编码将住宅建筑分配到网格中,并计算网格总面积(Python)。
- 根据面积将地区人口分配到网格中(Python)。
该解决方案在以下假设下是有意义的。
- 超市的目标顾客是槟榔屿的全体居民。
- 所有的住宅建筑可以分为两种类型:公寓和平房。
- 对于每个地区,公寓的居住密度是一致的。更具体地说,居住密度是指每 建筑面积的人口。
- 平房的居住密度在整个城市是一致的:每 100 平方米 5 个人。
第三个假设表明所有公寓共用相同数量的楼层。引入它是为了简化问题,因为 OSM 数据集中缺少建筑物高度信息。
实施演练
占地面积计算
将形状文件读入 dataframe 后,我们需要选择槟城住宅建筑的条目。这可以通过根据建筑物类型和建筑物的中心地理编码过滤数据帧来实现。中心地理编码是通过取建筑物所有顶点的纬度和经度的平均值来计算的。槟城的边界以下列地理编码范围宣布。
- 纬度:5.1175–5.5929
- 经度:100.1691–100.5569

图 3 槟榔屿住宅建筑的数据框架
可以根据建筑物顶点的地理编码来估计建筑物的占地面积。Mapbox 提供了一个 API 来计算 geojson 多边形或多重多边形的面积,可以在这里应用。
导出的数据如下所示。
Penang _ residential _ buildings . CSV
基于网格的城市离散化
该项目的最终目标是提出城市中超市网点的位置。因此,我们将创建网格,并针对各个网格分析需求和供应。插座的位置将以网格的形式提出。QGIS 是一个开源的桌面地理信息系统应用程序。它用于此目的,因为它提供了各种地图操作和可视化功能。将 OSM 形状文件导入 QGIS,并使用创建网格功能创建网格。
Vector -> Research Tools -> Create Grid

图 4 创建 QGIS 的格网功能
上图对话框中的网格范围用于定义网格覆盖的区域。我们可以选择“使用画布范围”选项来手动拖动选择一个覆盖槟城的矩形区域。生成的网格层如下图所示。

图 5 网格层的局部视图
为了分配建筑物和计算网格上的人口,我们可以将网格的边界信息从 QGIS 导出到文本文件和形状文件中。网格的 4 个边界在左、上、右和下列中产生,其遵循 EPSG:3857 ,一种由诸如谷歌和 OSM 的网络服务推广的球面墨卡托投影坐标系。在下一步中,它将被转换为正常的纬度、经度。区列是手动添加的,用来标记网格的父区。
Penang _ grid _ epsg 3857 _ WGS 84 . CSV
建筑物到网格的分配
在这一步,我们将根据建筑物的中心地理编码和网格的边界,将住宅建筑分配到网格中。在分配发生之前,建筑物和网格的坐标系统是同步的。
allocate _ buildings _ to _ grids . py

图 6 分配了网格的建筑物的数据框架
将地区人口分布到网格中
这是模拟的最后一步。我们将计算每个网格的总建筑面积,并根据网格的总建筑面积将地区人口分配到网格中。
公寓和平房的建筑面积需要分别计算,因为它们适用于不同的人口密度。
calc _ grid _ floor _ area . py

图 7 网格总占地面积的数据框架
然后,我们可以汇总各区的建筑面积,并估计不同区的人口密度。假设平房的统一人口密度为 5 人/ 100 米。
calc _ district _ pop _ density . py

图 8 不同地区的人口数据框架
现在让我们根据网格占地面积计算网格人口,我们就完成了!

图 9 网格群体的数据框架
我们可以将网格人口导出到 shape 文件,并在 QGIS 上生成人口分布热图。
generate _ grid _ population _ shape . py

图 10 槟榔屿市人口分布的局部视图
在图 10 中,网格数量随着色温的增加而增加(从无色、黄色、橙色到红色)。可以观察到,槟榔屿的人口主要集中在槟榔屿海峡沿岸,形成一个 X 形。
结束了
- 我们已经经历了一种模拟城市人口分布的新方法。该解决方案是使用开源工具和 OSM 数据集开发的。
- 由于假设居民密度一致,预计会有一些误差。此外,OSM 数据本身可能不是 100%正确和最新的。
谢谢你的阅读。代码库可以在 GitHub 上获得。请在媒体上关注我,了解我未来的博客。我欢迎反馈和建设性的批评,可以通过 LinkedIn 联系到我。
地理空间分析破解选址难题(下)
发现需求和供给之间的不平衡

图 1 在新加坡 FairPrice Finest 中巴鲁广场拍摄的照片
在本系列的第一篇博客中,我们提出了一个想法,旨在从需求和供给的角度解决选址问题。我们完成了需求方面的分析,并模拟了目标城市槟榔屿的客户分布。尽管案例研究是在食品杂货行业的场景中进行的,但同样的解决方案也可以应用于房地产、电子商务和教育行业。在这篇博客中,我们将解决供应方面的问题,并研究整个城市的需求和供应之间的不平衡。请记住,我们的客户是一家连锁超市,其潜在客户是整个城市的人口。
供应分析由以下部分组成。
- 竞争对手发现:寻找现有超市和杂货店的位置。
- 距离估算:估算参赛者与城市不同区域之间的距离。
- 顾客密度估算:估算一家超市或杂货店在城市不同位置服务的平均顾客数量。
竞争对手发现
使用 Google Places API 可以获得关于现有杂货店供应商的信息。它提供了关于不同类型的名胜古迹的各种信息,包括它们的商店名称、地理位置、开放时间,甚至游客评级等。这里我们期望 API 提供的信息是最新的。然而,并不能保证 API 可以检测到所有符合搜索标准的地方,尤其是欠发达地区。为了这项研究的目的,这是我们可以依赖的最好的可访问数据源。
Places API 使用 API 键,通常使用 3 个参数进行查询:设施类型、中心位置和半径。在第一个系列中,我们将整个城市区域分割成数千个 1 公里 x 1 公里的网格。为了通过 API 收集所有现有的杂货店供应商,我们获取网格中心的地理坐标,并搜索 2 公里范围内的超市和杂货店。为了使博客更简洁,代码更少,我将省略输入数据和配置参数的准备步骤,只强调如何查询 Places API。以下代码提取新加坡乌节路 2 公里范围内的超市。
查询结果以 Python 字典列表的形式返回。其中一个看起来如下。在这项研究中,我们只使用现有超市的地理位置信息。
{
"business_status":"OPERATIONAL",
"formatted_address":"491 River Valley Rd, #01-14, Singapore 248371",
**"geometry":{**
**"location":{**
**"lat":1.2929051,**
**"lng":103.8270208**
**}**,
"viewport":{
"northeast":{
"lat":1.294498079892722,
"lng":103.8284264298927
},
"southwest":{
"lat":1.291798420107278,
"lng":103.8257267701073
}
}
},
"icon":"[https://maps.gstatic.com/mapfiles/place_api/icons/shopping-71.png](https://maps.gstatic.com/mapfiles/place_api/icons/shopping-71.png)",
"id":"fda0ec60faa787f2bf992132e66c80f29daa5964",
"name":"FairPrice Finest Valley Point",
"opening_hours":{
"open_now":False
},
"photos":[
{
"height":2048,
"html_attributions":[
"<a href=\"[https://maps.google.com/maps/contrib/111973208857299784904\](https://maps.google.com/maps/contrib/111973208857299784904\)">Anusha Lalwani</a>"
],
"photo_reference":"CmRaAAAAQ6An4L-A5PbgDFkpZVllEGuB4Ayw0hdrZ9coCBaF6esLM2B7RVnJCvf0DPeZrlcbZ3KVFUz9cciPtArUAZ6tof_lJHzJHqKzcEFyRGJurK_Drld0GUec9sCWm25bXURVEhD6GZqf6j_Kb5IOTtQ1ogslGhQas22jzBT2rJ0jkj9zUhDvCLYj_w",
"width":1536
}
],
"place_id":"ChIJTyWXW4EZ2jERNKBCOx_-4LA",
"plus_code":{
"compound_code":"7RVG+5R Singapore",
"global_code":"6PH57RVG+5R"
},
"rating":4,
"reference":"ChIJTyWXW4EZ2jERNKBCOx_-4LA",
"types":[
"grocery_or_supermarket",
"food",
"point_of_interest",
"store",
"establishment"
],
"user_ratings_total":112
}
从所有网格中收集超市和杂货店,并在移除重复项后绘制在 QGIS 地图上,如图 2 所示。可以观察到,现有杂货店供应商的分布(白点)与客户分布大致一致。

图 2 槟城现有超市和杂货店的局部视图
距离估计
允许我问你一个问题。你愿意花多长时间在购物旅行上?
生活在不同城市的人可能会有不同的答案。我对这个问题的回答是 15 分钟的步行距离。在封锁期间,步行去杂货店可以作为一种常规的体育锻炼。在这项研究中,由于槟榔屿的人口密度相对较小,我们预计旅行时间的阈值会更长。根据马来西亚朋友的建议,我们假设阈值为 10 分钟车程。这是此分析中使用的最重要的参数,如果以后将解决方案部署为仪表板应用程序,可以很容易地对其进行调整。请注意,在咨询项目中,这些参数需要通过严格的市场调查获得。
这个旅行距离问题在这里很重要,因为,给定旅行时间的阈值,我们可以 估计每个杂货店可以接触到的顾客数量,这就是所谓的 流域分析 。为了便于分析,我们通过Google Distance Matrix API提取每对网格和现有杂货店之间的预计行驶时间。以下代码提取了从乌节路到新加坡滨海湾金沙的行驶时间。
结果表明,从起点到目的地址的行驶时间为 13 分钟。
{
"destination_addresses":[
"10 Bayfront Ave, Singapore 018956"
],
"origin_addresses":[
"2 Orchard Turn, Singapore 238801"
],
"rows":[
{
"elements":[
{
"distance":{
"text":"5.2 km",
"value":5194
},
"duration":{
"text":"13 mins",
"value":761
},
"status":"OK"
}
]
}
],
"status":"OK"
}
客户密度估计
让我们总结一下我们在网格级别获得的关键信息。
- 人口,或每个网格的客户数量。
- 为每个网格中的顾客提供服务的杂货店和超市的数量。
现在我们快速看一下网格中顾客和杂货店数量的分布。没有填充的网格在下面的直方图中被忽略。

图 3 电网客户数量的分布

图 4 10 分钟车程内的网格状商店数量分布
顾客和杂货店的数量看起来都很合理。在这里,我们将为每个网格计算一个客户密度指数,以评估整个城市的供需不平衡。从概念上讲,它相当于需求与供给之比 (DSR)。
顾客密度=顾客数量/网格中为顾客服务的杂货店和超市数量
我们将根据顾客密度值推荐新超市的位置。一般来说,高顾客密度意味着新商店的好位置。因此,我们的客户可以将其作为选址的参考。
图 5 显示了整个槟城的顾客密度分布。DSR 高的区域用深蓝色突出显示。

图 5 整个槟城的顾客密度分布
最后的话
选址案例研究系列到此结束。你可能已经注意到,在估计顾客密度时,超市的容量没有被考虑在内。换句话说,在这项研究中,所有现有商店的容量都是一样的,这在现实中是不准确的。此问题的一个可能解决方案是将现有商店与 OpenStreetMap (OSM)数据中相应的形状进行匹配。利用坐标可以计算出占地面积,并用来估计商店的容量。
此外,请在执行之前计划好您对 Google API 的查询。对查询数量和总成本进行估计。
本研究中使用的脚本和笔记本可在 GitHub 上获得。谢谢你的阅读。
破解 21 点—第 1 部分
破解二十一点
设置+简单的蒙特卡罗模拟
嗨!
我写这个“破解 21 点”博客系列是为了巩固我在强化学习领域获得的知识。当我创建这个 21 点项目时,我需要结合 30+文章和博客帖子的信息,我想让下一个人更容易。
我绝不是这方面的专家。如果您对我将要展示的信息有任何问题或疑虑,请随时联系我们!我的联系信息在底部。

图片来自 Unsplash
21 点快速总结
21 点是一种与庄家对抗的纸牌游戏。在一轮开始时,玩家和庄家都有 2 张牌。玩家只能看到庄家的一张牌。游戏的目标是让我们的牌的值尽可能接近 21,而不超过 21。下面列出了每张卡的价值。
- 10/杰克/皇后/国王→ 10
- 2 到 9 →与卡的值相同
- Ace → 1 或 11(玩家选择)
如果玩家的牌少于 21 张,他们可以选择“击中”并从这副牌中随机抽取一张牌。他们也可以选择“站”,保留手中的牌。如果玩家超过 21,他们“破产”并自动输掉这一轮。如果玩家正好有 21 点,他们自动获胜。否则,如果玩家比庄家更接近 21,则玩家获胜。
为什么要看这个帖子?
这篇文章的目的是展示即使是简单的模拟在模拟我们周围的世界中令人眼花缭乱的力量。对于任何强化学习的努力,最好是通过像 21 点这样的简单游戏来学习,因为它们只有一些不确定性要跟踪,明确的奖励和惩罚规则,以及一个直截了当的目标。
像 21 点这样的赌场游戏在统计上被设计成有利于“房子”,我有兴趣看看我是否能通过强化学习算法“破解”它。对于 21 点,我的目标是得出一个玩家策略,从长远来看,这个策略实际上会比赌场/庄家产生优势。****
一些关键术语
在这种情况下,策略是一个剧本,告诉玩家(或我们的人工智能代理)在每种可能的情况下应该做什么样的决定。人工智能代理是抽象的存在,它将通过我们的强化学习算法学习和更新它的知识。
在我们简化的 21 点模型中,我们只给玩家两个选项:打或者站。我们将以 1000 美元开始我们的玩家,并假设他们每轮下注 100 美元。以下是赢/输/平的奖励/惩罚:
- 赢:+100 美元
- 平局:0 美元
- 输了:$100
建筑 21 点
我建议在读完这篇文章后,按照你自己的速度浏览下面的代码。现在浏览一下代码,以便获得一些关于如何构建最适合您需求的模拟环境的想法。点击查看完整的笔记本。
上面代码的一个 TL:DR:
- 使用 OOP 原则(类、函数等)和基本数据结构(列表、字典等)定义了一张卡和一副牌。
- 定义了两个函数,用于实现庄家转牌和评估庄家牌局背后的逻辑。这里定义的和有一个固定的、可预测的逻辑。
- 定义了一个函数来实现评估玩家手牌背后的逻辑。有不同的方法来解决这个问题。
- 定义了一个主
play_game()函数,在给定玩家策略、回合数等参数的情况下模拟 21 点游戏。
本文剩余部分的重点将是研究这个模拟环境的玩家策略输入,看看我们能获得什么样的见解。
简单的蒙特卡罗模拟
任何蒙特卡罗方法的关键是:
"利用随机性来解决原则上可能是确定性的问题."— 维基百科
更简单地说,我们将依靠机器的计算能力来近似某些结论,而不是通过铅笔和纸来精确地得出那些结果。
蒙特卡洛方法的快速(非 21 点)示例
例如,让我们用蒙特卡罗方法来回答这个简单的问题:
“如果我掷出两个六面骰子,两个骰子的和最有可能是多少?”
正如每堂统计课所教授的那样,我们可以使用纸笔通过创建可能总和的概率分布来解决这个问题,并查看哪个出现的概率最大。
然而,如果我们懒得把这些都写出来,我们可以编写一个蒙特卡罗模拟程序来代替!
在下面的代码中,我将两个骰子掷 100,000 次,并绘制出我从 100,000 次模拟中得到的总和的分布。

来源:作者图片
瞧啊。我们从分布图中清楚地看到,掷出 2 个骰子时,7 是最有可能的和。计算能力的魔力!
回到 21 点
上面的骰子例子有点做作——蒙特卡罗方法最适用于需要人类花费大量时间尝试和手工解决的问题。
这里有一个更适合蒙特卡洛模拟的问题:
“在 21 点游戏中,如果我们的手牌≥ 18,我们就站着,否则就打,那么每回合的预期回报是多少?”
像这样的问题对人类来说太难解决了。
为了回答这个问题,我们将我们的玩家政策定义如下:
离散策略:
- 如果手≥ 18:站立。
- 否则:打。

来源:图片作者
运行模拟
接下来,我们将利用计算能力和 21 点环境的随机性来运行 100,000 轮并计算预期回报:

来源:图片作者
结果显示,如果玩家决定使用离散策略,平均来说,他们每轮会损失 10 美元。我们需要找到一个能产生更好回报的政策!
随机政策
离散策略被认为是“离散的”,因为只要满足一个条件(例如,手牌≥ 18),我们的玩家只会采取一种可能的行动。
然而,当我们设计我们的强化学习人工智能代理时,我们希望它有机会探索其他行为,即使一些标准告诉它做其他事情。对于我们的人工智能代理来说,在学习过程的早期阶段保持探索是很重要的,因为它的拣选动作策略是由太小的样本量决定的。
因此,我们需要习惯于随机变量和政策,这些变量和政策在选择行动时允许随机性。这里有一个我们可以试试:
随机策略:
- 如果手≥ 18: 80%站立/ 20%命中。
- 否则:80%命中/ 20%站立。
运行模拟

来源:作者图片
结果显示,如果玩家决定使用随机策略,平均来说,他们每轮会损失 18 美元(T1),比离散策略多 8 美元(T3)。尽管我强调了随机策略在强化学习中的重要性,离散策略还是赢了!
利用我们人类的直觉,我们可以理解为什么会发生这种情况。从长远来看,在牌局中继续击球总是更好< 18 and keep standing when hand ≥ 18. It is detrimental in the long run to add a 20% chance of doing a counter-intuitive action in either of these states.
However, our AI agent will not be born with this intuition. Stochastic policies are fluid, and can be tweaked on the fly. This approach allows our AI agent to suffer through countless rounds of hitting when hand ≥18, and incrementally tweak its policy until it stands 100% of the time when hand ≥ 18.
What’s Next
The upcoming installments of this series will strive to answer these questions:
- “玩 21 点的最佳方法是什么?
- “如何通过蒙特卡洛强化学习算法自发地学习这种最优策略?”
在我的下一篇文章中,我们将更深入地探究基本的强化学习理论。此外,我们将在 OpenAI Gym 的标准化框架内重建我们的 21 点环境。这将使我们能够轻松地探索算法和调整关键因素。
如果你想向前看,我的整个 21 点项目可以在这里找到。
感谢您的阅读!
我真的很感激任何形式的反馈!我想成为一个更一致、更有效的内容创作者。
你学到什么了吗?我很难理解吗?
欢迎在下面留言或发电子邮件给我,地址是 adithyasolai7@gmail.com!
请继续阅读!
破解 21 点——第二部分
破解二十一点
强化学习和开放式健身房简介
嗨!
如果您还没有这样做,请在继续之前阅读第 1 部分。本文的其余部分将假设您已经阅读并理解了第 1 部分。

图片来自 Unsplash
强化学习周期

作者制作的图像
为了推进我们使用强化学习“破解”21 点的任务,我们必须理解上图。下面,我将图像分解成它的组成部分,以及它们在 21 点中的对应部分:
- 代理:执行学习过程的人工智能抽象。在 21 点中,经纪人就是玩家。
- 环境:代理可以与之交互的所有可能情况的集合,每种情况下可用的动作,以及与每种情况相关的结果(奖励+惩罚)。在 21 点中,这是所有可能的玩家手牌、庄家向上的牌、玩家动作(打或站)和结果(赢/输/平)的集合。
- 陈述:有助于构成环境的“情境”。在我们的 21 点版本中,状态将由玩家的手牌值和庄家的上牌值组成。球员/经纪人在做决定的时候只能看到这两样东西。
- 动作:代理在与某个给定状态交互时可用的选项。在我们的 21 点版本中,可用的操作是击打和站立。
- 奖励:在某种给定的状态下,代理人收到的对其行为的反馈。这是由程序员定义的,以帮助向代理显示哪个结果是更好的,代理可以相应地开始调整它的动作。在我们的 21 点游戏中,赢=+100 美元,输=-100 美元,平=+0 美元。决定胜负/平手的逻辑在环境中;奖励是分配给每个结果的数值。
这些组件如何在 21 点中一起工作
- 一轮 21 点开始:2 张牌发给玩家和庄家,代理只能看到自己的牌和庄家的一张牌。环境通过向代理发送一个初始状态(玩家手牌值+庄家升牌值)来对此建模。

作者制作的图像
- 玩家有两个动作:打或站。代理使用其策略(在第一部分中讨论)基于当前状态选择一个动作。

作者制作的图像
- 代理选择的状态+动作被发送回环境。

作者制作的图像
- 在给定状态的情况下,环境在内部处理代理的动作。它为“击中”发任何新牌。如果合适的话,它会计算谁赢了这一轮(玩家站着,21 点!,或者半身像)。

作者制作的图像
- 如果这轮现在结束了,环境发送给代理一个代表下一轮 21 点的新状态,以及前一轮的奖励。代理使用该结果来更新其策略。

作者制作的图像
- 如果代理在当前回合中有更多的动作要做,则环境向代理发送一个状态,该状态具有更新的玩家手牌值和+$0 的奖励,因为该回合尚未结束。
我们的代理如何从这个循环中学习

作者制作的图像
上面的循环意味着这个循环将无限期地继续下去,那么实际的学习在哪里/什么时候发生呢?
单个周期可以表示为一个序列:
状态→行动→奖励
当我们围绕这个循环进行循环时,我们可以记录这些状态/动作/回报元组。在循环中经历大约“n”个循环,并在进行过程中记录状态/动作/奖励元组,这被称为情节。
在我们完成了我们期望的循环次数(假设 50 次)之后,我们的代理将遍历状态/动作/回报元组,并相应地更新它的策略。在下一篇文章中,我们将深入研究我们的强化学习算法将如何指导我们的代理使用这些状态/动作/奖励元组来优化它的策略。
偶发任务与连续任务
一集应该由多少个循环组成?在我的 21 点环境中,我认为一轮 21 点是一集。这意味着每集通常会有 1-3 个状态/行动/奖励元组,因为代理人在每轮 21 点中可能只会做出 1-3 个立/打决定(在极少数情况下会做出更多决定)。
幸运的是,我们在 21 点中有一个“回合”的概念来帮助定义一集。然而,其他上下文,如应用强化学习来预测股票市场,没有“回合”来帮助定义情节。股市是没有起点和终点的,在定义剧集的时候你必须要有创意!
由于这些原因,使用强化学习预测股票市场将被认为是一个持续的任务,而破解 21 点将被认为是一个阶段性的任务。
为什么要使用 OpenAI Gym 重建我们的 21 点环境?
我们在第 1 部分中设置的 21 点游戏没有准确模拟强化学习周期。我们遗漏了关键的部分,比如记录状态/动作/回报元组和定义一集。
我们将在 OpenAI Gym 的框架内构建新的 21 点环境。这个框架提供了一种定义我们环境的标准化方法,这样我们就可以很容易地用其他自己编写的和开源的强化学习算法进行实验。这个框架还提供了有用的 API 来更全面地定义我们的状态、动作和奖励。
我们新的 OpenAI 健身房 21 点环境概述
为了构建我们的环境,我们将在 OpenAI Gym 环境模板中定义函数。这些函数是对强化学习的循环过程建模的必要部分,如下所示:
__init__():初始化 21 点牌组,奖励空间(+$100,+$0,或-$100),动作空间(击打或站立),观察空间(或所有可能状态的集合。每个状态由玩家手牌值和庄家升牌组成)。reset():重置剧集,给代理初始状态。step(action):代理使用我们的算法选择一个动作,并使用这个函数将这个动作发送到环境中。这个函数模拟环境的过程(击中时发新卡,计算奖励等)。然后,它返回一个新的状态,奖励,以及该集是否完成。render()(推荐):显示一集不同阶段的状态/动作/奖励元组等相关信息的功能。无助于循环往复。
使用 OpenAI 健身房 21 点环境
在深入研究这些函数的代码之前,让我们看看这些函数如何一起工作来模拟强化学习周期。在下面的模拟中,我们使用我们的 OpenAI 健身房环境和随机选择击中/站立的策略来寻找每轮的平均回报。

图片作者。查看代码此处。
- 首先,我们初始化环境:
env = BlackjackEnv()。该行将运行前面描述的__init__()功能。 - 然后,我们运行 1000 集(或 1000 轮 21 点)的模拟。
- 在每集开始时,我们调用
env.reset()函数给代理一个新的初始状态,以确定 hit/stand。 - 在
step()函数中将环境的env.done值更改为True之前,代理会随机选择击中/站立作为其对step()函数的动作。在下一篇文章中,我们的算法将改进拣选动作的过程。 - 一旦
env.done到了True,这一集就结束了,这一集的总奖励加到总奖励里,下一集开始。在下一篇文章中,我们的算法将向代理展示如何在每一集之后改进其策略。
构建开放式健身房 21 点环境
下面的代码片段包含了我在 OpenAI 健身房环境中实现的 21 点。现在先浏览一下,在完成这篇文章后再详细浏览。我在下面详细介绍了每个功能的关键线路。这些函数重用了第 1 部分中内置的一些函数和类。
**__init__()** :
首先,我们利用 OpenAI Gym 的spaces功能来定义我们的动作空间:击打或站立。我们使用两个二进制选择的离散集合:0 表示击中,1 表示站立。

图片作者。查看代码此处。
接下来,我们定义观察空间。观察空间是代理可以观察和响应的所有可能状态的集合。在我们的 21 点版本中,状态是玩家的手牌值和庄家的上牌。
观察空间是强化学习循环中环境的一个组成部分。其他组件,如计算奖励和玩家手牌值,在step()函数中实现或从第 1 部分重用。
我们考虑的可能牌值范围是 3 到 20。2 是不可能的,因为它需要两个 a,而我们计算手牌值的逻辑不会将两个 a 评估为 2。对于手牌值 21(21 点!)和 beyond(半身像),代理人不需要做任何决定。
所有可能的庄家大牌从 2 到 a。Ace 仅由 11 表示,而不是 1。在我们的算法中,代理在学习和优化时并不关心庄家的 Ace 评估为 1 还是 11。
玩家的牌值范围是 3 到 20,也就是 18 个离散值的范围。庄家升牌的范围是 2 到 Ace,这是一个 10 个离散值的范围。我们再次使用 OpenAI Gym 的spaces函数来表示这一点。我们还使用spaces.Tuple来表示这两个范围必须相乘才能得到所有可能的状态。

图片作者。查看代码此处。
最后,将环境的done变量初始化为False,以确保在一集结束前玩满一轮 21 点。

图片作者。查看代码此处。
**reset()**T14:
如前所述,该函数重新使用第 1 部分中的函数来重置和重新洗牌,向玩家和庄家发 2 张牌,并评估玩家的手牌价值。
该函数还将初始状态作为一个包含两个值的numpy数组返回:玩家的手牌值和庄家的上牌。

图片作者。查看代码此处。
**step(action)** :
该函数接收代理的动作。调用_take_action(action)函数来发一张新卡,如果动作被击中,则重新计算玩家的手牌值。

图片作者。查看代码此处。
然后,该功能会在服用action后查看二十一点的插曲现在是否完成。

图片作者。查看代码此处。
如果这一集已经结束,那么这个函数将重新使用第 1 部分中的逻辑来决定赢家和奖励。
最后,该函数返回新状态、奖励以及该集是否完成。{}是一个返回值,用来描述函数中发生了什么,但是我们现在让它为空。

图片作者。查看代码此处。
**render()** :
这个函数只是使用简单的print()函数来显示玩家的手牌值、玩家手中的牌、庄家的上牌以及env.done的值。
该函数主要用于调试。
下一步是什么
在接下来的文章中,我们将利用我们定制的 OpenAI Gym 环境和强化学习的新知识来设计、实现和测试我们自己的强化学习算法!
我们将使用首次访问蒙特卡罗方法对我们的算法进行建模,并调整关键杠杆,如γ(贴现率)、α(学习率)和ε(探索与利用)以最大化回报。
我们一直在讨论的一切最终将在下一篇文章中汇集在一起。我们将最终指导一个人工智能代理有机地学习一个最优策略来破解 21 点!
感谢您的阅读!
我真的很感激任何形式的反馈!我想成为一个更一致、更有效的内容创作者。
你学到什么了吗?我很难理解吗?
欢迎在下面留言或发电子邮件给我,地址是 adithyasolai7@gmail.com!
请继续阅读!
破解 21 点——第三部分
破解二十一点
强化学习算法的构建模块
嗨!
如果您还没有这样做,请在继续之前阅读第 1 部分和第 2 部分。本文的其余部分将假设您已经阅读并理解了前面的文章。

图片来自 Unsplash
这篇文章的大纲
在本文中,我将解释强化学习算法中使用的关键构建模块,我们将使用它来最大化 21 点回报。这些构建模块也在许多其他强化学习算法中使用,因此在我们知道并喜爱的上下文中理解它们是值得的:二十一点!
当你阅读这篇文章的时候,一定要记住第二部分中的强化学习循环图!

作者制作的图像
我们 RL 算法的构建模块
简而言之,我们的强化学习算法唯一会做的事情就是在每一集之后,用状态→动作→奖励元组(在第二部分中解释)来定义代理应该做什么。下面描述的构建模块有助于我们的代理在学习过程中进行更新,以获得玩 21 点的最佳策略。
我们的算法将使用和更新的关键数据结构
- Q 表:记录给定状态下选择动作的值(或 Q 值)的表。Q 表是通过从第 2 部分的中获取 21 点环境中定义的
observation_space和action_space的叉积构建的。所有状态/动作对的初始 Q 值都是 0。 - Prob 表:以与 Q 表相同的方式创建的表:
observation_space和action_space的叉积。此表包含代理在给定状态下选择动作的概率。这加强了在第一部分中描述的政策的随机方法。每个状态的行动的初始概率将是 50%命中/ 50%站立。 - Q 表和 Prob 表定义了一个活的、呼吸的、随机的策略,我们的代理将不断地使用它来做出决策,并在从环境中获得回报后进行更新。
影响代理学习过程的重要变量
- Alpha (α): 这可以认为是学习率。当我们的代理在某个状态下从环境中获得行为奖励后,它将更新 Q 表中相应状态-行为对的 Q 值。α是 Q 值变化的权重(或系数)。α必须是> 0 且≤ 1。较低的 α意味着每一轮 21 点对政策的影响较小,并且有助于在大量事件中进行更准确的学习。

作者制作的图像
- Epsilon (ε): 这可以被认为是 Prob 表中概率的类似“学习率”。当我们的代理人因某个状态+行动获得奖励时,它也会调整未来采取相同行动的概率。ε将与α相似的权重/系数应用于这些变化中的每一个。ε必须≥ 0 且≤ 1。更高的ε产生更小的采取行动的概率变化。****

作者制作的图像
- ε衰变(ε-衰变):这是每次发作后ε衰变的速率。在代理学习过程的开始,我们希望ε从高开始,对 Prob 表进行小的修改,因为我们希望我们的代理探索新的行动。这有助于确保最终的政策不会因为学习过程早期的随机性而严重扭曲。例如,我们不希望在学习过程的早期对 player-hand-value = 18 进行几次成功的“hit”操作,以使我们的代理人决定从长远来看 hit 在这个位置是正确的。随着学习过程的继续,我们使用ε-decay 减少ε,因为我们希望代理利用它在先前的探索阶段获得的准确见解。

作者制作的图像
- ε最小值(ε-min): 探索 vs 利用动态非常微妙;如果不小心,从探索到利用的转变可能会非常突然。ε-min 变量设定了一个事件对概率表中某个状态的动作概率的影响限度。
- Gamma (γ): 在给定的一集(或一轮)21 点中,AI 智能体在某些情况下会做出不止一个决定。比方说,当玩家手牌值= 4 时,我们的 AI 智能体命中,并在此之后再做出 2 个决策。在这一集的最后,代理人得到了一份奖励。最初的“击中”动作对最终的奖励有多大的责任?γ有助于解释这一点。我们使用γ作为一集最终奖励的贴现率,来近似初始“击中”动作的奖励。γ必须为> 0 且≤ 1。

作者制作的图像
上面的变量应该被认为是杠杆:它们可以被增加或减少来试验代理的学习过程。稍后,我们将讨论这些杠杆的哪种组合在 21 点中产生最佳策略和最高回报。
下一步是什么
在下一篇文章中,我将从高层次上解释首次访问蒙特卡罗算法,然后深入代码。我将展示我是如何实现本文中描述的算法和所有构件的。
类似于第 2 部分中的 OpenAI Gym Blackjack 环境,该算法的实现通过几个关键的 Python 函数协同工作来实现。
感谢您的阅读!
我真的很感激任何形式的反馈!我想成为一个更一致、更有效的内容创作者。
你学到什么了吗?我很难理解吗?
欢迎在下面留言或发电子邮件给我,地址是 adithyasolai7@gmail.com!
在此阅读第 4 部分。
破解 21 点——第四部分
破解二十一点
初访蒙特卡罗算法+编码吧!
嗨!
如果您还没有这样做,请在继续之前阅读第 1 部分、第 2 部分和第 3 部分。本文的其余部分将假设您已经阅读并理解了前面的文章。

图片来自 Unsplash
这篇文章的大纲
在这篇文章中,我将解释首次访问蒙特卡罗(MC)算法是如何工作的,以及我们如何将其应用于 21 点,以教会人工智能代理最大化回报。下面是这篇文章的结构:
- 从高层次解释算法。
- 在第二部分的中的 OpenAI Gym Blackjack 环境中实现算法。
在阅读时,请记住,首次访问 MC 算法的主要影响是定义代理在某个给定状态下采取某个行动获得奖励后应该如何更新其策略。请参考下面的图表来帮助形象化这一点。

作者制作的图像
首次访问 MC 算法的 10,000 英尺概述
- 从第 2 部分初始化 21 点环境。
- 定义第三部分中解释的 Q 表、概率表、α、ε、ε衰减、ε最小和γ。
- 定义您希望您的代理学习多少集。更多的情节通常会产生更有利可图的政策。
- 播放一集。记录剧集中所有的(状态→动作→奖励)元组。
- 剧集结束后,对ε应用ε-decay/ε-min。
- 然后,使用来自步骤 4 的(状态→动作→奖励)元组和相关公式更新 Q 表和概率表。
- 对于步骤 3 中定义的剧集数量,重复步骤 4-6。
- 在所有事件之后,产生的 Q 表和概率表代表了 AI 代理刚刚学习的 21 点的优化策略。
更详细的步骤 4-6
在上面的概述中,我故意对第 4、5 和 6 步解释不足。这些都需要代码和公式来正确解释,这就是我在这里要做的!我建议打开完整的笔记本,快速查阅我提到的、我没有深入研究的任何更小的功能。在这里找到它。
第 4 步:播放一集
我们将利用第 2 部分中定义的 21 点环境的功能来模拟一集。我们还将利用 Q 表和概率表。
浏览下面play_game()函数的代码片段。之后我会分解关键步骤。
- 使用第二部分中描述的
env.reset()功能开始一集二十一点。reset()函数返回一个state:代理必须做出决定的初始状态。这将在我们播放剧集时更新。当我们播放这一集时,一个列表episodes将存储所有的(状态→动作→奖励)元组。

作者制作的图像
- 播放一集的全部意义就是记录并返回我们的代理人通过做决定和拿回奖励而产生的(状态→动作→奖励)元组。我们的算法将使用这些元组来改变定义我们的代理策略的 Q 表和概率表。

作者制作的图像
- 当
env.done变成True时,我们这一集就结束了。这在第 2 部分的中有解释。

作者制作的图像
- 如果给代理发了 21 点(21!)幸运的是,在这一集开始时,这一集被废弃了。我们的人工智能代理无法从这一事件中学到任何东西,因为它不需要做出任何决定。我们将返回一个空的
episode列表。(我们检查state[0] == 19,而不是 21,因为我们将所有玩家手牌值减去 2,以满足我们的 21 点环境中的observation_space。)(参见第二部分或代码。)

作者制作的图像
- 否则,代理必须决定一个行动:打或站。它使用 Q 表来确定对于给定的
state,哪个动作当前具有最高值(或 Q 值)。这个**state**的击中和站立的这些 Q 值将在本集之后在我们算法的步骤 6 中更新。

作者制作的图像
- 接下来,ε(出自第三部)和探索和开拓之间的微妙平衡就要发挥作用了。我们使用这个概率表来找出选择
best_action的概率。然后,我们使用这个分布随机决定一个动作。如果我们由于低ε而处于利用阶段,则best_action极有可能被选中。如果我们由于高ε而处于探索阶段,我们的代理有更大的机会选择best_action的反面。这是该算法如何利用随机策略和蒙特卡罗方法的一个完美例子:它使用随机性来处理本质上确定性的问题。这个**state**的这些击中和站立的概率将在本集之后在我们算法的步骤 6 中更新。

作者制作的图像
- 接下来,代理使用
env.step()函数提交到action_to_take(参见第 2 部分了解更多关于env.step())。代理收到一个next_state并因其动作获得奖励。env.done也更新了。

作者制作的图像
- 我们仍然可以访问
state——我们开始时的状态。我们仍然可以访问action_to_take——我们在state采取的行动。我们也是刚刚收到state里拿action_to_take的reward。所以我们有一个(状态→动作→奖励)元组要添加到episode!

作者制作的图像
- 最后,我们设置
state = next_state重复这个过程,直到env.done变为True。
我们将在这里停止这篇文章,因为我想让这些信息以更小的、一口大小的部分来消化!
下一步是什么
在下一篇文章中,我们将直接深入讨论步骤 5 和步骤 6 ,就像我们讨论步骤 4 一样。
在理解了步骤 5 和步骤 6 之后,你将了解这种强化学习算法的所有技术方面。然而,解决人工智能/人工智能问题既是一门科学又是一门艺术
在之后的文章中,我们将更深入地探讨这个 21 点问题的艺术部分。我们将通过对α、ε和γ进行实验,展示如何优化该算法。
感谢您的阅读!
我真的很感激任何形式的反馈!我想成为一个更一致、更有效的内容创作者。
你学到什么了吗?我很难理解吗?
欢迎在下面留言或发电子邮件给我,地址是 adithyasolai7@gmail.com!
在这里阅读第五部分。
破解 21 点——第五部分
破解二十一点
完成首次访问蒙特卡罗算法
嗨!
如果您还没有这样做,请在继续之前阅读第 1–4 部分。本文的其余部分将假设您已经阅读并理解了前面的文章。

图片来自 Unsplash
这篇文章的大纲
- 了解
run_mc()函数如何简化算法。 - 深入研究初诊 MC 算法的第 6 步,在这一步中,Q 表和概率表在每集之后更新。
第 4 部分首次访问 MC 的 10,000 英尺概述
- 从第 2 部分的中初始化 21 点环境。
- 定义第三部分中解释的 Q 表、概率表、α、ε、ε衰减、ε最小和γ。
- 定义您希望您的代理学习多少集。更多的情节通常会产生更有利可图的政策。
- 播放一集。记录剧集中所有的(状态→动作→奖励)元组。
- 剧集结束后,对ε应用ε-decay/ε-min。
- 然后,使用来自步骤 4 的(状态→动作→奖励)元组和相关公式更新 Q 表和概率表。
- 对于步骤 3 中定义的剧集数量,重复步骤 4-6。
- 在所有事件之后,产生的 Q 表和概率表代表了 AI 代理刚刚学习的 21 点的优化策略。
如何促进第 4-6 步
在第 4 部分中,我们学习了如何在play_game()函数中实现步骤 4。在深入到第 5 步&第 6 步之前,我想介绍一下run_mc()函数,它允许第 4 步到第 6 步协同工作。
浏览下面的代码。我将在下面详细解释。点击查看完整的代码。
实现关键数据结构和值
run_mc()是明确定义 Q 表和 Prob 表的地方。
Q 表存储每个可能状态的每个动作的相对值(或 Q 值)。同样,状态由玩家的手牌值和庄家的上牌组成。
为了在 Python 中表示这一点,Q是一个二维列表,其中外部列表的每个索引对应于一个唯一的状态,每个内部列表是一个 2 元素的 Q 值列表,用于命中和站立在与索引对应的状态。
numpy.zeros()函数允许我们指定想要用来表示 Q 表的 Numpy 数组的形状,从而简化了这个过程。我们还希望所有的 Q 值都从 0 开始,以便在代理开始试验和探索选项时不会产生偏差。numpy.zeros()通过用零填充我们指定的 Numpy 数组来实现这一点。
根据我们在第 2 部分中的 21 点环境,env.observation_space[0].n是 18,代表可能的玩家手牌值(3–20),而env.observation_space[1].n是 10,代表可能的庄家升牌值(2–11)。env.action_space.n是 2,因为唯一可能的行动是打和站。
因此,可能的状态数为env.observation_space[0].n * env.observation_space[1].n,为 180。这意味着Q的外部列表有 180 个值。Q中的这 180 个值中的每一个都是一个大小为env.action_space.n(或 2)的内部零列表。
Q = np.zeros([env.observation_space[0].n * env.observation_space[1].n, env.action_space.n], dtype=np.float16)
我们以完全相同的方式定义 Prob-table(或prob ) ,,除了每个值从 0.5(或 50%)而不是 0 开始,以确保每个动作在学习过程开始时有均等的机会被选中。
prob = np.zeros([env.observation_space[0].n * env.observation_space[1].n, env.action_space.n], dtype=np.float16) + 0.5
run_mc()也是第 3 部分中讨论的重要杠杆(ε、α和γ)被明确定义的地方。赋予每个值背后的原因将在下一篇文章中解释。
alpha = 0.001
epsilon = 1
decay = 0.9999
epsilon_min = 0.9
gamma = 0.8
步骤 4–6 协同工作
这几行代码概括了所有的步骤 4-6。
**for** _ **in** range(num_episodes):
episode = play_game(env, Q, prob)
epsilon = max(epsilon * decay, epsilon_min)
Q = update_Q(env, episode, Q, alpha, gamma)
prob = update_prob(env, episode, Q, prob, epsilon)
首先,我们使用第四部分中讨论的play_game()功能模拟一集。这是第四步。
然后,我们将decay因子应用于epsilon,或者如果epsilon已经低于epsilon_min,就使用epsilon_min。这是第五步。
最后,我们使用update_Q()和update_prob()更新我们的 Q 表和 Prob 表。episode和epsilon是这些功能的关键论据,而且每集都有变化。这是第 6 步。
深入第 6 步
在我继续之前,祝贺你读到这里!你将要学习这个蒙特卡罗过程的最后,也是最重要的部分。你已经走了很长的路了!花点时间思考一下吧!
update_Q()
之所以称之为“首次访问” MC 算法,是因为我们有一种首次访问的方法来评估奖励。
“首次访问”意味着我们希望从一集第一次出现开始跟踪状态-动作对的奖励,然后使用该集的累积奖励来更新我们的Q-表中该状态-动作对的 Q 值。
另一个选项是“每次访问”方法。在这种方法中,每当 在一集中出现时,我们使用状态-动作对的即时奖励来更新 Q 值。
鉴于 21 点的形式以及我们如何设置我们的环境,对我们的问题使用每次访问的方法是没有意义的。
在我们的剧集中,除了最后的状态-动作对,状态-动作对的奖励都是 0。这是因为在 21 点回合(或插曲)的结果已知之前,21 点玩家(和我们的代理人)可能必须做出不止一个决定(意味着不止一个国家行动对)。
因此,如果我们强迫我们的代理在每个状态-动作对之后使用$0 的即时奖励来更新 Q 表中的 Q 值,我们的代理将不会有很大的改进。相反,我们将使用最终状态-动作对的奖励,并贴现它们,以近似同一集内先前状态-动作对的价值。
我们将使用以下公式为每集中的状态-动作对找到折扣奖励:

作者制作的图像
计算折扣奖励的示例如第 3 部分所示:

作者制作的图像
一个直观的例子:

作者制作的图像
放在一起:对于episode中的每个(状态→动作→奖励)元组,我们将使用状态-动作对的折扣奖励来更新Q表中相应的 Q 值。
以下是我们这一集遇到的每个状态-动作对的 Q 值变化公式:

作者制作的图像
update_Q()本质上为我们这一集看到的每个状态-动作对计算⍙ Q ,并将⍙ Q 加到当前 q 值上。实现如下。
下面是我们episode中每个状态-动作对的贴现奖励的计算。step在前面已经定义过了,本质上是我们公式中的 i 下标,它记录了我们正在分析的状态-动作对。
total_reward = 0
gamma_exp = 0
**for** curr_step **in** range(step, len(episode)):
curr_reward = episode[curr_step][2]
total_reward += (gamma ** gamma_exp) * curr_reward
gamma_exp += 1
下面是⍙ Q 的计算,并使用它来更新我们的Q表中相应的 q 值。
*# Update the Q-value*
Q_state_index = get_Q_state_index(state)
curr_Q_value = Q[Q_state_index][action]
Q[Q_state_index][action] = curr_Q_value + alpha * (total_reward - curr_Q_value)
在学习过程的最后,我们可以简单地查看我们的Q-表,看看对于任何给定的状态,哪个动作具有更大的相对值。
update_prob()
请多花点时间消化update_Q()。如果你完全理解了update_Q(),那么update_prob()就轻而易举了!
为了刷新你的记忆,update_prob()调整了在我们的剧集中遇到的每个状态采取行动的概率分布。update_prob()在update_Q()结束后被调用,因为 Q 值影响概率更新的方式,我们需要最新的 Q 值。
这次我将从代码开始,因为update_prob()的公式比简单得多。
在update_prob()中,我们使用Q表来找出哪个动作(击打或站立)对于我们正在更新的状态具有更大的 Q 值。这是best_action。
首先,我们调整给定状态下选择best_action的概率。⍙ 概率的计算公式如下(其中prob[Q_state_index][best_action]是选择best_action的当前概率):
⍙**Prob =** prob[Q_state_index][best_action] + 1 - epsilon
⍙ 概率有可能超过 1(或 100%),所以我们更新prob表中的概率如下:
prob[Q_state_index][best_action] = min(1, ⍙**Prob**)
最后,我们将根据best_action的新概率更新other_action的概率:
prob[Q_state_index][other_action] = 1 - prob[Q_state_index][best_action]
更新这些概率很重要,因为这将影响我们学习过程中的探索与利用动态(详见第 3 部分)。
学习过程开始时较小的⍙ 概率值确保了在best_action成为代理的主导选择之前需要一段时间。接近结束时较大的⍙ 概率值将最终导致best_action的概率为 100%,代理可以开始总是采取它认为是最优的决策。
下一步是什么
恭喜你。你现在知道“破解”21 点背后的所有科学!接下来,我们将深入到试验这种算法的艺术中,以找到可能的最佳 21 点回报!
感谢您的阅读!
我真的很感激任何形式的反馈!我想成为一个更一致、更有效的内容创作者。
你学到什么了吗?我很难理解吗?
欢迎在下面留言或发电子邮件给我,地址是 adithyasolai7@gmail.com!
用强化学习破解因果
使用强化学习来推断因果关系可能会打开机器学习的新领域,并可能避免另一个人工智能冬天

推断因果的困难无处不在。人类每天都面临这一挑战,并且在克服这一问题上做得非常出色,至少与我们的动物近亲相比是如此。Yoshua Bengio 等机器学习先驱甚至建议,创建可以推断因果的算法是避免另一个人工智能冬天和解锁机器智能新前沿的关键。在这篇文章中,我解释了强化学习是如何被重新构建来推断因果关系的,类似于我们人类这样做的能力,也许有一天会远远超过它。
对于那些不熟悉强化学习的人来说,它指的是用于确定顺序决策任务中的最优性的算法子集。它通常表现为一个代理人学习在一个环境中采取一系列行动来获得奖励。这些算法很容易应用于可以“游戏化”的问题,从而有明确定义的行动和奖励。最近,强化学习算法因在围棋、星际争霸和各种视频游戏中击败人类而广受好评。
这种强化算法取得成功的基本手段是通过连续的反复试验训练使预测误差最小化的概念。该方法相当准确地对应于人类多巴胺学习系统,该系统也利用预测误差。
有两个主要障碍使得推断因果关系成为一个难题,一个是复杂性,另一个是相关性。接下来我将解释强化学习如何被重新构建来解决这些问题。
如前所述,强化学习通常表现为一个主体在一个环境中为追求某种回报(比如赢得一场游戏)而做出一系列决策。代理可以采取行动,根据环境的状态,这些行动要么得到奖励,要么没有。当他们得到奖励时,代理将这种奖励传播回所有导致它最终获得奖励的行为和环境状态。通过多次试验,它可以确定哪些行为和环境状态的组合有助于获得奖励,哪些是多余的。从另一个角度来看,代理确定哪些行为和环境状态的组合与它获得奖励有因果关系,哪些没有。实际上,代理正在推断因果关于它自己的行为和环境的特定回报状态。
重要的一点是,从根本上说,RL 算法对于来说是不可知的,环境中的哪个组件是代理,哪个仅仅是对象。我们可以把环境中的所有对象看作可能的代理,把一个对象可能存在的所有状态看作它的动作集,而不是从代理、它的动作和环境的角度来考虑。这样,环境中给定的一组组件和特定的最终状态之间的任何因果关系都可以通过简单地改变哪个对象是代理以及被奖励的最终状态是什么来探索。
让我们用一个例子来解释这个问题。RL 的一个相当常见的演示是匹配样本任务,其中代理人(通常是一种小型毛茸茸的哺乳动物)必须学会采取一系列行动来获得食物奖励,例如,当灯亮时按下控制杆。经过训练,许多动物和人工智能机器人都可以解决这类任务。(参见强化学习代理解决样本匹配任务的附带视频)
现在想象我们是一个天真的社会科学家,不知道这个实验是如何设计的,并且希望知道是什么导致食物奖励被解锁。换句话说,我们想知道匹配样本任务背后的因果故事。回答这个问题的一个潜在方法是采用 RL 算法,该算法顺序地通过环境中的对象,将每个对象视为“代理”,并尝试查看该代理/对象是否可以采取一系列动作来最小化关于解锁食物奖励的预测误差。与打开食物碗的奖励状态有因果关系的对象将具有一些动作,这些动作允许它最小化关于该奖励状态的预测误差。一个没有因果关系的将没有这样的状态/动作组合,不管它的动作集合与奖励状态有多好的关联。
记住,在我们的重构中,动作只是指一个对象可以存在的不同状态。例如,我们可以以这样的方式提出这个问题,打开和关闭的灯是代理,它的动作也是打开和关闭的。如果在我们选择作为代理的任何对象的行为和我们想要理解的回报状态之间存在因果关系,那么也存在关于其行为空间的预测误差,该误差可以通过连续的训练集被最小化。换句话说,有一种方式,这个对象/代理可以因果地影响奖励状态。
解开环境中因果关系故事的一种潜在方法是迭代地移动环境中的对象,将它们视为采取行动的代理,并检查哪一个导致了关于奖励状态的可以最小化的预测误差。同样,与奖励状态没有因果关系或者仅仅与奖励状态相关的对象在其动作空间上将具有预测误差,该预测误差基本上是随机的,并且不会随着更多的训练集而减少。以这种方式,RL 提供了一种在算法上探测给定环境中的元素的因果关系的方式,依次将每个元素视为试图通过一些动作来改变其行为以便影响奖励状态的代理。
此外,预测误差减小的速率,通常被称为代理学习曲线,将给出一些指示,表明对象/代理与奖励状态的因果距离。虽然蝴蝶扇动翅膀可能会在地球的另一边引起飓风,但是与最小化关于更接近的原因的预测误差所需的训练集的数量相比,预测这种情况所需的训练集的数量将是天文数字。因此,在所有其他条件都相同的情况下,学习曲线在衡量相对因果接近度方面非常有用。
有许多假设和限制适用于这种方法,即所有那些适用于强化学习本身。它还假设我们有一种方法来评估环境中每个代理/对象的动作空间,并且这满足马尔可夫特性。在匹配样本任务的例子中,环境中的每个对象都有一个小的明确定义的动作空间。对于具有大的或连续的动作空间的对象,探索因果关系可能变得难以计算。同样值得注意的是,这个用于推断因果关系的系统只适用于可以产生大量样本试验的情况,正如 RL 本身只适用于“自我播放”允许大量训练集的情况。虽然这可能是一种探索因果关系的计算密集型方法,但随着计算成本的降低,越来越多的环境可以通过这种方法接近。
科学的持久挑战之一仍然是确定复杂系统中的因果关系。例子包括人类基因组,其中无数的基因和环境因素促成了特定的表型。在这种情况下,因果关系可能很难推断,这种方法可能有助于揭示哪些"行为者"或国家有助于实现特定成果。它还向能够“解释”用于确定特定行动过程的因果推理的代理人开放了人工智能领域。另一个潜在的应用是生成先验知识,通过这些知识,人工智能可以存储以前推断的因果关系列表,并在遇到挑战性问题时将它们应用到新的行动空间。这种先验知识可以极大地减少成功完成一项任务所必需的训练,并可能导致人类所展示的一次性学习。
破解数据科学面试
重点是技术问题

图片鸣谢:https://www . datanami . com/2018/09/17/improving-your-odds-with-data-science-hiring/
技术问题
问题有几个类别,根据你面试的地点,问题的难度会有所不同。这篇文章的目的是介绍这些类别,并强调一些相关的问题。讨论的问题来自 https://datascienceprep.com/的,涵盖了顶级科技公司的面试问题。
可能性
问这些问题是为了证明你理解概率的基本原理。常见主题包括:联合概率和条件概率以及概率的各种规则和定理(乘法法则、包含-排除等。)很多时候,它们纯粹是技术性的“脑筋急转弯”问题,可能与特定产品有关,也可能无关,其难度从容易的一端(a)到困难的一端(b)不等。
示例:
a)假设您正在推出一项新功能 X。你有 1000 个用户,每个用户要么是 X 的粉丝,要么不是。1000 个用户中有 50 个不喜欢 x。你将在独立抽样 5 个用户的基础上决定是否发布该功能,如果他们都喜欢该功能,你将发布它。您发布该功能的可能性有多大?
B)有两组 n 个用户,A 和 B,A 中的每个用户都是 B 中的用户的朋友,反之亦然。A 中的每个用户将随机选择 B 中的一个用户作为他们的好友,B 中的每个用户将随机选择 A 中的一个用户作为他们的好友。如果两个人都选择了对方,那就是相互最好的朋友。不会有互相最好的友谊的概率是多少?
统计数字
这些问题旨在测试您的基本统计基础——虽然通常不直接适用,因为您通常不会从头开始编写 A/B 测试,但更多的是为了让您可以在必要时调整实验,并理解和解释结果。常见的主题包括各种分布,中心极限定理和大数定律,假设检验,等等。这些问题从更多的“脑筋急转弯”(a)到更多的与产品相关的开放式问题(b),前者需要以简洁的方式应用统计概念。
示例:
a)您可以玩两种与骰子相关的游戏。在第一场游戏中,你同时掷出两个骰子,并获得与掷骰子的结果相等的金额。在第二个游戏中,你掷出一个骰子,得到相当于该值平方的金额。哪个期望值更高,为什么?
b)你如何决定一个实验进行多长时间?仅使用固定的 p 值阈值存在哪些问题,您如何解决这些问题?
产品
产品问题是专门为手头的公司设计的,为了衡量你对一个很可能与公司相关的特定主题的直觉。因此,重要的是要始终适应你面试的公司,以及他们生产的产品类型和跟踪的指标。通常,主题将包括从比较和对比平台(a)到理解特性变化如何影响特定指标(b)的任何内容。
示例:
a)想象一下脸书和推特的社交图。它们有什么不同?你会用什么标准来衡量社交图表的偏斜程度?
b)你的团队正在试图弄清楚一款具有额外 UI 功能的新司机应用程序是否会增加乘车次数。你如何测试应用程序中的额外功能是否使它比原始版本更好?
编码
由于数据科学需要精通编程,这里的编码在风格上类似于你可能找到的软件工程角色的面试水平。常见的主题包括数组、链表、字典,并经常利用基本算法,如 BFS 和 DFS。
示例:
a)给定一个数 n,返回连续正整数列表的个数总和为 n,能在线性时间内完成吗?
b)你有一个完整的用户社交图,节点代表用户,边代表用户之间的友谊。给定图的边和节点数,写一个函数返回两个用户之间的最小数量的友谊。
结构化查询语言
与编程类似,数据科学需要 SQL 技能来快速查询和分割数据。这些通常很简单,涉及基本原理,偶尔也涉及窗口函数。和产品问题一样,它们往往相当实用。
示例:
a)假设您在 app analytics 上有一个事件表。写一个查询,得到 2019 年每个 app 的点击率。
b)假设您有用户拥有的会话表和一个用户表。编写一个查询来获取每日群组的活动用户计数。
机器学习
虽然并非所有数据科学职位都直接或间接利用机器学习,但如果你正在寻找更高级的数据科学或机器学习工程职位,那么在应用和理论方面都有良好的熟练程度肯定会有所帮助。根据你面试的公司,这里的话题会有很大的不同,因此问题的范围可以从针对特定应用的更面向产品的问题(a)到更具体的理论问题(b)。
示例:
a)假设您需要为欺诈检测生成一个二元分类器。您会查看哪些指标,每个指标是如何定义的,每个指标的解释是什么?
b)假设我们正在运行一个概率线性回归,它很好地模拟了一些 y 和 x 之间的潜在关系。现在假设所有输入都添加了一些噪声,这与训练数据无关。新的目标函数是什么?你是怎么计算的?
感谢阅读!
如果你有兴趣进一步探索不同类别的面试准备问题,请查看:https://datascienceprep.com/
制作一个机器学习模型,使用 R

图片由 education_free 在 Freepik 上拍摄
建模一个 ML 实验来预测 R
学生保留率是高等教育中最重要的指标之一。因此,预测分析在这方面发挥着至关重要的作用。
首先,让我们从定义什么是学生保持开始,至少在本文的范围内。我们将把它定义为一个指标,它告诉我们,一个在某个特定的秋季学期第一次进入大学的学生,是否会在下一个秋季回来(或不回来)。例如,假设一名学生在 2018 年秋季第一次开始上某所大学。如果这名学生报名参加了 2019 年秋季课程,那么这名学生将被保留。
保留的另一个常见名称是,持续,和/或退出。在这里,这些名字的意思是一样的:一年本科留级。此时,读者可能会问,“为什么学生保留率无论如何都很重要?“这是一个很好的问题,我们没有必要穷尽这个答案,我们可以说这很重要,原因有很多,首先是财务影响、学校可以获得的排名和声望,还有很多。顺便说一下,当我们在这里说“学校”时,我们特指大学和学院(高等教育)。
寻找合适数据集的挑战
找到一个学生级别的数据集是非常困难的——如果你有一个,想发给我,请这样做,但它必须是匿名的。这意味着,没有学生的姓名或 ID,或任何其他信息,使研究人员能够识别学生——特别是,当我们有适当的法规,保护学生的数据,如 FERPA。这是一件大事,我们在处理敏感信息时必须非常小心。
也就是说,明确地为这个实验定位正确的数据集,确实是一个挑战。然而,积极的一面是,我们设法找到了一个可以使用的数据集,这就是我们将在这里操作的数据集。你可以在 UCI 机器学习资源库找到,点击这里就可以了。
为了使用这些数据,我们需要进行适当的引用,请参考本文的“参考资料”部分。另外值得一提的是,为这些研究者提供了这个数据集。谢谢你。
棍子和石头
虽然我们发现了这个数据集,但事实是,对于机器学习(ML)项目来说,它实际上是一个小数据集,除此之外,我们稍后会看到,变量在大的事物方案中并不真正相关。所以,最终,ML 模型可能会有一个很差的性能。我们会继续讨论这个问题。
另一个需要强调的重点是,最初,这个数据集是用来预测学生的表现[1],而不是保留。有趣的是,数据集具有有趣的特征,但在预测性能[1]和保留时没有相关的意义。我在这里的意思是,尽管我们有几个变量,但基本上,只有很少一部分能告诉我们历史。
我们实验的布局
我们将在这里运用大量的创造力。注意,原始数据是关于高中学生的。但是对于这里,我们假设那些学生是大学生。此外,我们必须创建并整合一个名为“”的新功能,该功能是随机创建的,用于模拟学生是否被保留。显然,这对模型有负面影响,因为这实际上是我们的预测变量——而且是随机的。
尽管如此,进行这个实验的主要目标是提供一个可用的机器学习管道,特别是使用正确的数据集,以利用高等教育中的学生保留率。我希望这个 ML 项目可以帮助这方面的管理者和研究者。下面是我们如何将我们的任务分成如下四个主要阶段:

图 1 —主要阶段概述
- 第一阶段:数据管理
在这一阶段,我们将寻找缺失的数据,并熟悉数据集。奇怪的是,我们在这里没有发现任何缺失的数据。虽然有人可能认为这很好,最终也确实如此,但这也让我们思考,在我们使用这个数据集之前,是否进行了一些插补。这里有一个提示:当您决定输入缺失值时,请记录下来,将缺失值留在原始列,将插补值留在新列。此外,如果您刚刚放弃,请说明使用了哪种技术来输入值。通过阅读与该数据集一起使用的原始文章,我们得出的结论是丢失的数据被遗漏了,我们得到的是实际的响应,这意味着我们没有丢失的值。
- 第二阶段:探索性分析
在不知道哪些变量在特定数据集中真正相关的情况下,我永远无法理解那些执行“探索性分析”的人。不要到处乱画图表。有一些最初的假设是没问题的,但是你应该总是试图弄清楚什么特征对于你正在试图研究的东西是重要的。所以,我们的一些图表是基于我们发现的相关的和我们想看到的,但主要是基于对数据集的科学理解。
- 第三阶段:降维
在我看来,最重要的一步。特别是,因为这个数据集非常小,而且有相当多的变量。在这里,我们将寻找多重共线性,以及如何消除变量。我们将使用逻辑回归来剔除不相关的变量。除此之外,我们还将执行 PCA (主成分分析),目的是找出相关特征。
- 第四阶段:机器学习
这就是我们执行 ML 建模并获得惊人结果的部分,对吧!?事实证明,这一阶段相当具有挑战性,我们稍后会谈到这一点。但我们在这里使用的一些技术是使用 ROSE [2]库来平衡预测值,评估 AUC(曲线下面积)和 ROC 曲线,并检查多个算法的准确性和 kappa 分数,以便检查每个算法对该数据的最佳效果。
最坏的情况:假设得到一个低性能的机器学习模型
小数据集往往会给 ML 算法带来挑战。尤其是当特征并不真正重要,并且预测因子是人为创建的、随机的且不平衡时。真是一场灾难啊。!
考虑到这一点,甚至在实际开始使用该数据集之前,我们就提出了以下假设,但不限于此:

图 2 —低性能的假设
上面我们可以看到六个主要假设和它们的一些原因。由于时间关系,我们不会在这里一一介绍,但是在编码和开发模型时,我们会尽可能地减轻它们的影响。请注意,不平衡和随机分类器问题是为此项目创建的,它们不是原始数据集的一部分。
请记住,我们预测这些问题的原因与我们人为创建了一个名为 retention 的新功能有关,该功能根据赋予它们的权重,对二进制值(1 或 0)进行随机排序。
为了说明这一点,我们使用的数据集中的学生总数仅为 649 人,在创建这个人工预测值时,我们说大约 85%的学生将被标记为“保留”(二进制指标为 1),大约 15%的学生将被标记为“未保留”(二进制指标为 0)。这几乎是公立学院/大学的平均保留率。
弄脏我们的手:是时候编码了!

Sarinya9940 在 Freepik 上拍摄的照片
我们使用名为 R 的统计和开源应用程序来执行这项任务。并且,为了使它在视觉上更吸引人(这是我们的希望),我们不会在这里显示所有的代码,但是您可以在如下所示的链接中找到所有的代码。
所有代码和文件都可以在我的 GitHub 页面的 这里找到 。
同样,我们将把这一动手部分分解成我们之前看到的四个阶段。事不宜迟,让我们从头开始:
阶段 1:数据管理
同样,你可以在 UCI ML 知识库中找到原始数据集和论文。但是,这里有一个所有变量的快照:

表 1-预处理的学生相关变量。该表摘自原始论文[1]。
请记住,我们之前谈到的保持力变量是人为插入到该数据集的,目的是模拟学生保持力的预测模型。你在这张表中看不到,但在 R 代码中可以看到。还有两个数据集可用,一个是数学数据集,一个是葡萄牙语数据集。我们将只使用葡萄牙语的,因为这是一个有更多学生(649)的。文章[1]将数学和葡萄牙语合并到一个集合中,但是样本量更小。
此阶段 1* 的主要目标之一是创建人工变量,熟悉该数据集,并检查缺失值。*

图 1 —缺失值
正如我们在图 1* 中看到的,该数据集中没有缺失值。事实上,我们以前已经说过了,但这里有证据。请注意,我们在该图中添加了保留值变量。*
此外,我必须为数据集中的一些变量创建伪变量,这些变量不是伪编码的。在该处理结束时,可以使用提供的 R 代码导出一个新的 csv 文件,其中包含虚拟代码、数值和预测值。
既然我们已经开了绿灯,数据集也准备好进行初始评估,我们就可以进入下一步了。
阶段 2:探索性分析

照片由 Freepik 上的 sema_srinouljan 拍摄
这就是人们疯狂绘制直方图和箱线图的地方,不是吗?!他们是必要的,不要误解我。我们一会儿就会看到其中的一些。此外,您还可以在 R 代码上检查诸如偏斜度、峰度等基本的统计检查表。

图 2 —保留计数(保留= 1.0,未保留= 0.0)
在这个简单的条形图中,我们可以看到预测变量的计数,根据我们在创建这个人工预测器时为它们设置的权重。
如前所述,保留的学生标记为“1”(538),未保留的学生标记为“0”(111)。
最终,它也显示了分类器之间的不平衡,我们将在后面处理。
在最初的文章[1]中,变量“G1”是学生表现的一个非常强有力的预测因素。下面的散点图告诉我们一年级(G1)和期末(G3)之间预期的正相关关系。我们还可以发现一些潜在的异常值。

图 3 —散点图 G1/G3
继续这个分析,我们有兴趣看看什么会影响学生在 G1 的表现。为此,我们重点检查了学习时间,以及学生可用的空闲时间,并按性别进行了细分。

图 4-标准化平行坐标图
好吧,我投降!在这里,我想出了一个所有变量的方框图。我们可以很容易地在这里看到异常值的存在,并快速思考是否要处理这个问题的一些选项。对于这个测试,我们不会排除异常值。

图 5 —所有变量的箱线图
再一次,我想给变量 G1 一些关注,所以让我们检查它的分布如下:

图 6 —可变 G1 的直方图/箱线图
考虑到这是真实世界的数据,它的分布真的不算太差。但是,它显然并不完美。
作为第三阶段的总结,我们只想再检查一件事。也就是说,当将学生添加到二元图中时,G1 和 G2 变量是如何相互作用的,如下所示:

图 7——G1 和 G2 变量的二元图
把这个二元图想象成一个普通的箱线图,但是混合了两个变量而不是一个。具体来说,蓝色的数字可能是学生 ID(这里不是这样,因为我们在数据集中没有学生 ID)。任何在大椭圆之外的学生都是离群值。这可能有助于确定我们应该联系哪些学生,以便采取一些积极的行动,比如说,提高他们在 G3 上的成绩。
阶段 3:降维
这就是乐趣的开始。一个好的做法是始终检查数据集中的共线性/多重共线性。最简单的方法是检查自变量和因变量之间的相关性。如果两个或更多变量具有非常强或几乎完美的相关性,这可能是共线性/多重共线性的迹象。
当面对两个或更多变量具有强相关性的场景时,我们希望消除其中一个变量。为什么?因为本质上,你有两个变量告诉你同一个故事。但是说得更专业一点,共线性可能会扰乱至少一个估计回归系数的方差,这可能会导致一些回归变量得出错误的符号。这会影响你的分析并把你引向错误的方向。
让我们用下面的相关矩阵来看看是否能发现一些问题:

图 8——所有变量的相关矩阵
这里有一些有趣的相关性,但主要是关于等级(G1、G2 和 G3)。它们似乎有很强的相关性,表明存在潜在的共线性。我们也看到成绩和失败之间有很强的负相关性,还有其他一些特征。您总是可以使用相关表来检查实际数字,或者直接在图上添加它们。现在,我们只想对变量之间的关系有一个大致的了解。
主成分分析(PCA) 用于将原始变量塑造成一组新的特征,这些特征是原始变量的线性组合。主成分分析的主要目标是减少变量的数量,但尽可能考虑原始变异。
在第一个分量或维度中,您将看到原始变量的组合,其样本方差在所有可能的线性组合中是最大的。在第二维中,我们考虑剩余方差的最大比例,它可以与第一维不相关。其他组件遵循类似的方法。
当分析运行 PCA 的输出时,我们希望看到一维和二维之间的“累积比例”,这是有意义的。一般来说,累积比例等于或大于 0.7 被认为是非常好的。也就是说,从多个变量缩减到两个维度仍然可以很好地代表整个数据集。
在执行 PCA 之前,一件重要的事情是确保数据集是标准化的。在这一点上,决定是否移除异常值也是一个好的做法。
为了使用 PCA 开始我们的分析,我们将从一个条形图开始,它显示了所有成分之间的累积比例以及它们的方差。

图 9——五氯苯甲醚累积比例
本质上,我们特别感兴趣的是将我们的分析缩小到前两个维度。我们希望确保它们之间的累积比例足以“解释”数据集的其余部分。
不幸的是,正如你将在下一张图中看到的,累计比例仅为 21% (12.9% + 8.1%)。因此,减少到两个维度是不推荐的,因此,我们将丢失信息,并最终得到两个不能“解释”数据集的维度。

图 10—尺寸 1 和尺寸 2 的 PCA 双标图
从双标图中,我们还可以看到变量之间的相关性,例如等级(G1、G2 和 G3)和指向相反方向的故障。虽然两个维度的累积比例在归结到该数据集的维度减少时并不真正有用,但我们希望检查每个维度的前十个变量的贡献。这可能有助于我们更好地理解这个数据集。
**
图 11-Dim 1 和 Dim 2 的 PCA 贡献
我们可以看到,在 Dim 1 中,等级是该维度贡献最大的变量。但是,需要强调是,这里仍然存在共线性假设。所以这是又一个线索,事实上,我们在这里可能有共线性,因为我们看到所有的等级都有非常相似的贡献水平。另一方面,在 Dim 2 中, Walc 特性的贡献最大。
总之,如果有人问 Dim 1 和 Dim 2 是关于什么的,我们可以说 Dim 1 是关于学生成绩的,Dim 2 是关于学生饮酒量的。这意味着,在预测保留率时,我们应该预期这些变量中的一些具有统计显著性。
所有这些测试在指导我们决定哪些变量应该保留,哪些变量应该忽略时都非常有帮助。不幸的是,我们还不能使用 PCA 来做任何决定。
回过头来看,我们有共线性的假设仍然存在,但是如何测量它,以及如何决定去掉每个变量?
鉴于对这一问题的认识,并考虑到这一点,我们将利用 VIF(可变通货膨胀系数)来检测并支持我们在处理多重共线性时采用最佳方法的决策。简而言之,VIF 检测变量之间的相关性有多强,它的分数指导我们在每个变量上降低和减轻共线性。
根据一般经验,VIF 分数等于或大于 5 表示共线性。我们在这里也将使用 5 作为阈值。正如我们在下面看到的,基于逻辑回归的 VIF 输出告诉我们,G2 和 G3 是我们在进一步分析中应该忽略的变量。

图 3 — VIF 输出
通常情况下,您应该去掉当时的一个变量,然后再次运行分析。也就是说,G2 是第一个离开的,G3 是第二个。这里有一个图形化的方法来显示移除这两个变量(G2 和 G3)之前和之后的情况:
**
图 12-在阈值 5 处检测到共线性(左侧)。未检测到高于 2.5 的共线性(右侧)。
作为所有这些争论的结果,我们只是去掉了两个变量。从某种意义上说,这并不是真正有成效的。我们仍然有一个相当大的功能集,它并没有告诉我们要做什么。因此,我们的捷径将是使用逻辑回归,不仅帮助我们找到预测,而且消除非统计意义上的变量。

图 4 —逻辑回归输出
正如从 Logit 回归输出(在左侧)中注意到的,我们有五个变量可以作为预测因子。
然而,其中只有三个在 0.05 处有显著性,我们用红色箭头标出。
**R 平方是一些研究人员在选择模型时可能使用的一个常用指标。这里,我们将只使用 AIC(赤池信息标准)分数来比较具有 5 个变量的输出和具有 3 个变量的输出。
正如你在下面看到的,消除两个不太重要的变量并不会对 AIC 分数产生太大影响。
- 所有五个统计显著变量:AIC: 589.84
- 所有三个统计上显著的变量在 0.05:AIC:589.67 米
是的,整个数据集的 AIC 更大(622.4),但因为它充满了并不真正有用的要素,我们在这里绘制了这条曲线,并决定在下一阶段只处理这三个变量。
第四阶段:机器学习

考虑到我们到目前为止所面临的所有挑战,在建模 ML 模型时可能会出什么问题呢?糟糕的性能模型可能会出错。但是,我们希望得到最好的结果,至少是一个公平的模型。
也就是说,我们在这里必须是真实的,ML 非常适合大型数据集。但是经过一些调整,我们可以让它工作。在这种情况下,我们将利用名为 ROSE 的库来平衡预测器并提高模型的性能。
最初,我们的预测器是这样分割的:1= 538,0= 111。你可以清楚地看到,我们有一个不平衡的分类器。我们将人为地平衡它,以改善结果,并减轻随之而来的一些统计问题。然而,我们将对列车拆分的数量进行评估。因此,我们的列车车组共有 553 名学生,其中:1= 458,0= 95。换句话说,我们现在将平衡训练数据,而不是整个数据集。
ROSE 提供了一些不同的选项来平衡分类器。我们将涵盖 4 种不同的方法,并选择一种给我们最好的结果。下面是我们从论文《ROSE:二进制不平衡学习的一个包》[2]中借用的代码。
*### Balancing the data:
**# Resampling Option 1 (over):**
data.bal.ov <- ovun.sample(retention ~ ., data = trainSplit, method = "over", p=0.5, seed = 2)$datatable(data.bal.ov$retention)**# Resampling Option 2 (under):**
data.bal.un <- ovun.sample(retention ~ ., data = trainSplit, method = "under", p = 0.5, seed = 2)$data
table(data.bal.un$retention)**# Resampling Option 3 (both):**
data.bal.ou <- ovun.sample(retention ~ ., data = trainSplit, method = "both", N = 553, p = 0.5, seed = 2)$data
table(data.bal.ou$retention)**# Resampling Option 4 (ROSE):**
data.rose <- ROSE(retention ~ ., data = trainSplit, seed = 1)$datatable(data.rose$retention)*
- 重采样选项 1 (over): 这里我们对“0”进行过采样,直到它与“1”的计数持平。因此,我们将分类器平衡如下:1= 458,0=453。
- 重采样选项 2(下):通过对多数类(1)进行欠采样以匹配少数类,我们得到这个结果:1=97,0=95。
- 重采样选项 3(两者):在这种情况下我们使用整个 train 集合(553)并拆分,比如:1=281,0=272。
- 重采样选项 4 (ROSE): 最后我们用 ROSE 来拆分数据,得到了这个结果:1=293,0=260。
接下来,我们训练分类器,使用分类树运行测试集,并绘制 ROC 曲线。
*# Training the Classifiers and run test set using classification trees:
library(rpart)
tree.ov <- rpart(retention ~ ., data = data.bal.ov)
tree.un <- rpart(retention ~ ., data = data.bal.un)
tree.ou <- rpart(retention ~ ., data = data.bal.ou)
tree.rose <- rpart(retention ~ ., data = data.rose)# Predict in the new data (test):
pred.tree.ov <- predict(tree.ov, newdata = testSplit)
pred.tree.un <- predict(tree.un, newdata = testSplit)
pred.tree.ou <- predict(tree.un, newdata = testSplit)
pred.tree.rose <- predict(tree.rose, newdata = testSplit)# Plot ROC Curve - Model Evaluation:
roc.curve(testSplit$retention, pred.tree.rose[,2], col = 0, main= "AUC: 0.75", lty = 1)
roc.curve(testSplit$retention, pred.tree.ov[,2], add.roc = TRUE, col = 12, lty = 2)
roc.curve(testSplit$retention, pred.tree.un[,2], add.roc = TRUE, col = 0, lty = 3)
roc.curve(testSplit$retention, pred.tree.ou[,2], add.roc = TRUE, col = 0, lty = 4)*
重采样选项 2(下)为我们提供了最佳 AUC(曲线下面积)输出。见下文:

图 13 —重采样选项 2 的 ROC 曲线(下)
AUC 是一种算法,广泛用于测量所述 ML 分类器的真阳性(TP)率和假阳性(FP)率之间的权衡。
同样地,预测失败的模型得分为 0%,而能够做出“完美”预测的模型得分为 100%。
相应地,我们的模型得分为 75%,这还不算太差,但是一个≥80%的数字会更好。
从积极的一面来看,使用 ROSE 包给了我们一个巨大的改善。所以,我们会庆祝这是一个巨大的胜利。耶!
衡量分类器的另一个非常常见的方法是通过决策树,这将使我们对模型的表现有更多的直觉。这里我们将跳过这一步,转到 ML 分析的下一步,也是最后一步。
通过准确度和 Kappa 选择机器学习模型
很多人依靠准确性来选择 ML 模型。仅仅这一点可能会引起误解,但是因为这是一个非常 【快速和肮脏】 类型的项目,我将允许我自己尝试一下。
- 准确性:它基本上指出了被正确标记的“1”和“0”的比例。
- Kappa: 告诉我们与随机分配的值相比,分类器的性能。
下面是我们处理这部分分析的方法:我们将再次使用 ROSE 来平衡整个数据集(649 行)。这次我们不会在训练和测试之间拆分,那是因为集合非常小。我们将利用我们拥有的一切。
类似地,我们将使用下面的代码来平衡预测值,但是正如您将看到的,我们人工复制了多达 1298 个观察值的数据集,并且在这里使用了“both”方法。
*# Create balanced training data for LR:
dataC <- ovun.sample(retention ~ ., data = dataC, method = "both",
N = 1298, seed =1)$data # 1298 (649x2)
table(dataC$retention)*
因此,我们得到了新的平衡分类器,例如:1=652,0=646。现在,我们将使用“ mlbench ”库来运行几个不同算法之间的基准比较,以查看每个算法是否具有最佳性能。

图 14-箱线图 ML 模型选择。你可以在这里找到源代码。
正如我们在上面看到的,这种分析的“最佳”算法是 svm (支持向量机),其准确率接近 70%,而 kappa 为 39%。这些是公平的结果,但肯定不是最佳的。
请记住,在选择实际用于生产的每个型号时,必须考虑许多其他因素,而不仅仅是准确性得分。为了我们试图完成的目的,我们的 ML 分析到此结束。
最后的想法
总之,你看到三个主要的预测器是 Medu 、 famsup_yes 和 Dalc 。下一步将是从 Logit 回归中获得优势比,并使分析更具可解释性。我将把它留给将来的改进,以节省我们的时间。
提醒一下,我们这里的目标是提供一些如何使用多种技术来处理小数据集并获得相当好的结果的指南。有许多其他方法来解决这个问题,这里我们提供给你一个可靠的方法——使用真实世界的数据集。
有了一个设计更好的适合预测保留的数据集,有了更多的观察,我们当然可以期待有更好的结果。该分析就是为此目的而创建的。
最终,保留率是高等教育中最重要的指标之一,这一管道有助于进一步研究这一主题,并有助于管理员根据数据做出更好的决策。
下次见!
参考资料:
[1] P .科尔特斯和 a .席尔瓦。使用数据挖掘预测中学生成绩。在 a .布里托和 j .特谢拉编辑的。,第五届未来商业技术会议论文集(FUBUTEC 2008)第 5–12 页,葡萄牙波尔图,2008 年 4 月,EUROSIS,ISBN 978–9077381–39–7。
[2] Nicola Lunardon、Giovanna Menardi 和 Nicola Torelli。ROSE:Binay 不平衡学习包。R 杂志第 6/1 卷,2014 年 6 月。国际刊号 2073-4859。
[3] Whitlock,Joshua Lee,“使用数据科学和预测分析来了解 4 年制大学学生流失”(2018)。电子论文。3356 号文件。https://dc.etsu.edu/etd/3356
CRAIG:客户评论分析洞察生成器
使用 NLP 和 TextBlob 分析客户评论的情感指标

杰里米·蔡在 Unsplash 上的照片
你好!希望大家在疫情爆发期间保持安全和健康。
今天我想分享一个有趣的项目,是我的团队在 Gesture 做的。对克里斯多佛·里吉奥和梅格娜·穆拉利哈兰的快速大喊,感谢他们成为令人敬畏的团队成员。
在衡量公司业绩或评估公司底线指标时,CRAIG dashboard 不是高管们日常使用的仪表盘,而是一种创新而实用的数据应用,用于推动行为分析。该项目旨在通过分析我们公司产品的评论来更好地了解客户体验,并确定产品中可能代表趋势或洞察力的方面。
不用说,评论是企业衡量产品和服务表现的一种重要方式。通过它们,我们可以确定哪些因素推动了好的和坏的客户体验,并允许公司有改进的空间。通过分析 Yelp 和 Google Places 等在线业务平台上存在的大量客户评论,公司能够调整其产品和服务,以更好地满足客户的需求,从而提高保留率和积极的品牌知名度。
在按需礼品交付应用程序 Gesture 中,我们利用自然语言处理和数据辩论技术,使用客户评论分析洞察生成器 CRAIG 来洞察产品评论和。有了 CRAIG,我们可以在粒度和聚合级别上更深入地了解单个客户的体验。通过提取和分析来自 Yelp 的产品评论,CRAIG 建立了实际应用程序来帮助各部门的工作,例如:
- 根据评论向 Yelp 客户进行个性化营销推广
- 基于顾客偏好和推荐的 SKU 新产品构思
- 与积极和消极情绪相关的手势产品和类别分析
- 对竞争对手和潜在合作伙伴的洞察
那么,CRAIG 有哪些功能呢?
- 正负关键词跟踪系统
- 对客户情绪的趋势洞察
- 具有搜索功能的评论
- 洞察推动客户体验的因素
为了提供一个直观的分析,这里是克雷格的样子。

CRAIG(一个 2x2 的自动化 Tableau 仪表板)
我们从 Yelp 网站上收集了来自加州、伊利诺伊州和纽约三个州的花店和纸杯蛋糕店的超过 20,000 条评论。收集数据的脚本是通过谷歌云功能按计划触发的,在这里数据被抓取、清理并安全地加载到我们的谷歌云平台上。
正面关键词


肯定关键词图表是按计数频率对最肯定关键词的直观表示。它显示增加评论平均评分的关键词(二元模型和三元模型的组合)。每个条形的颜色表示情绪-颜色越暗,包含该关键字的评论越积极,颜色越暗,包含该关键字的评论越消极。
这些发现验证了我们的直觉,即的客户服务对于一个健康且表现良好的企业来说绝对至关重要,评级良好的企业极有可能被推荐给他人。最后一分钟送货也很重要,这也是 Gesture 努力成为按需送货服务,在一小时内将礼物送上门的原因。
如果你想知道数据是如何被清理的,评论需要一些预处理步骤,包括单词的小写,删除标点符号和停用词,评论的标记化和词条化。通过使用 TextBlob 包和基于位置(州)和日期的过滤来生成 ngrams。
负面评论


负面关键词图表遵循与正面关键词相同的结构,但显示的是导致负面评价的负面关键词。图表上的颜色是较浅的蓝色,表明积极情绪比积极评价中观察到的情绪要少。
我们看到交付是差评中的一个常见问题,在这种情况下,客户因服务不满意而不得不打电话回来,或者产品没有按时交付或根本没有交付。黄玫瑰似乎也不是受欢迎的选择。
按情感和评级的关键词


“按情感和评级列出的关键字”图表是一个可视报告,允许用户按情感和评级发现关键字。这两个参数呈正相关,特定评论的评分值越高,客户对其体验的评价就越积极。每个圆圈的颜色在 CRAIG 的所有网格中保持一致,每个圆圈的大小对应于计数。圆圈越大,该关键词在整个评论语料库中被提及的频率就越高。
搜索评论


最后一个网格是所有评论、供应商和作者的数据库,用户可以通过在搜索框中输入关键字来搜索任何评论。它还可以选择导航到第一列中的每个用户配置文件。
克雷格到此为止。CRAIG 旨在将所有客户评论集中到一个仪表板中,提取来自社交渠道的数据,并允许企业更好地与客户互动。感谢您的阅读,祝您有美好的一天!
用 Libra 创建一个复杂的机器学习模型
非专家使用的一行建模查询

韦斯·希克斯在 Unsplash 上的照片
在最近一段时间,有许多与数据相关的项目爆炸,尤其是以机器学习为骨干的项目。在商业行业项目中,许多机器学习被应用于创建预测模型(预测事件、搅动、欺诈等)。).
所有机器学习的问题是,我们需要学习复杂的代码,结果有时对于非专家来说太复杂了。
基于以上原因,现在有一个面向非专家的机器学习 python 包叫做 Libra 。这个包的前提很简单:他们优先考虑易用性和人体工程学;意思是用尽可能少的行创建一个机器学习模型。
磅
那么,这个天秤座套餐到底是什么?根据他们的说法,它是一个机器学习 API,让我们只需一行代码就可以构建和部署机器学习。多整洁啊!
此外,目标检测、预处理和评分是默认完成的。我们只需要选择模型并输入数据。
让我们试试它是如何工作的。
在我们安装 Libra 包之前,我们需要安装 Python 3.6 或更高版本。任何低于这个数字的都不行。要安装这个包,我们只需要在命令提示符下运行下面的代码。
**pip install libra**
在你安装完这个包之后,我们会尝试这个包是如何工作的。让我们准备好所有需要用到的东西。首先,出于我们学习的目的,我将使用来自 Kaggle 的关于教育的数据集这里是。下图是数据信息。

现在,假设我们想要创建一个预测模型来对类列进行分类。利用天秤座,一切都变得简单了。
#The only thing we need to import**from libra import client**
在 Libra 中,数据集仍然需要从外部读取;比如说 CSV 文件。这就是为什么我们要创建一个直接读取文件的客户端类。
#Creating a client object that read the data to create the prediction model**edu_client = client('xAPI-Edu-Data.csv')**
上面的代码是我们所需要的;下一部分更像是以我们想要的方式查询模型,并立即得到结果。
目前,Libra 中唯一的机器学习模型是:
- 神经网络
- 卷积神经网络
- 支持向量机
- 最近的邻居
- 决策图表
- k 均值聚类
还有几种自然语言处理,包括:
- 文本分类
- 文档摘要
- 图像字幕生成
虽然,对于我们的情况,我们只会尝试使用神经网络模型。让我们试着创建预测模型。为了创建预测模型,我们需要从客户端方法调用我们想要的机器学习。
在我们的例子中,应该是.neural_network_query在参数中接受一个文本。我们传递的查询是一个简单的英文文本,如‘classify the class’或‘estimate accurate the StudentAbsenceDays’。重要的是目标列;您需要在查询中指定它。之后,API 会预测这是一个分类问题还是回归问题。让我们看看下面的例子。
#Creating the model by simple query, for example classify the class. Using Libra, you would need to specify which column you want as the target and the rest would be preprocessed automatically**edu_client.neural_network_query('classify the class')**

只需使用一个简单的查询,就可以自动对模型进行预处理,并启动学习过程。此外,所有的重复过程和指标也会立即显示出来。

此外,该模型为我们提供了每个时期的精度和模型损失图。
如果你想知道你能在模型中传递的所有参数,请在这里查阅 API 指南。
Libra 还提供了对模型更深入的分析。我们可以通过运行下面的代码来访问分析。
**edu_client.analyze()**


上面,我们得到了总体指标,包括 ROC 曲线和混淆矩阵。有了这个,我们可以更快地分析我们的模型。
结论
在本文中,我概述了如何使用 Libra 在一个模型中创建机器学习预测。几乎所有繁琐的部分都由 API 完成,我们只需要看到结果。
这并不意味着它可以取代数据理解和功能工程,因为 API 的主要部分是创建一个机器学习模型,而不是创建新的功能。
希望有帮助!
如果您喜欢我的内容,并希望获得更多关于数据或数据科学家日常生活的深入知识,请考虑在此订阅我的简讯。
如果您没有订阅为中等会员,请考虑通过我的推荐订阅。
使用 R,Shiny & Plotly,一眨眼的功夫就能看到新冠肺炎案例数据
创建并发布一个 web 应用程序来可视化冠状病毒的数据

自冠状病毒新冠肺炎成为疫情以来,世界上至少有一半人在关注这一病例统计数据。我也是。作为一名数据科学家,我很好奇,所以我访问了案例统计数据并创建了一些可视化。通过这篇报道,我将告诉你如何自己做同样的事情。没有魔法!
测试一下:【https://go.aws/3aoYsIW
本演练解释如何创建 web 应用程序和交互式绘图。基于 R & Shiny 的开源技术栈非常单薄。大约 120 行代码就足够了。
代码也可以从 GitHub 下载。链接可以在本文的底部找到。
目标
本文的目标是能够创建一个运行 web 应用程序的,它每 30 分钟更新一次数据,并在仪表板上显示这些数据。该应用程序的特点是:
- 冠状病毒官方可用数据的下载和解析。
- 下拉菜单选择国家和州。
- 显示所选国家新的和累积的病例统计数据的两个图。可以显示确诊病例、痊愈病例和死亡病例。
任务
- 设置 R & RStudio。
- 设置 R 项目及其文件夹结构。
- 使用 Shiny 创建用户界面。
- 添加加载和预处理数据的逻辑。
- 添加服务器逻辑。
- [可选]将应用程序上传到云。
设置 R & RStudio
首先从https://rstudio.com/products/rstudio/download/#download下载 R 的 base 版本,启动安装程序并通过。
然后,从https://rstudio.com/products/rstudio/download/#download下载 RStudio 桌面的免费版本。再次启动安装程序并完成步骤。
现在安装我们需要的包。启动 RStudio 应用程序并进入控制台(通常位于左下方的窗口)。通过键入以下命令安装软件包:
> install.packages("shiny")
> install.packages("dplyr")
> install.packages("tidyr")
> install.packages("plotly")
设置 R 项目及其文件夹结构
在 RStudio 中,单击右上方的下拉菜单“项目:(无)”,然后选择“新建项目…”。

点击“新目录”,然后点击“闪亮的网络应用”。现在为您的项目选择一个任意的新目录名,例如“ corona-app ”。此外,选择您希望应用程序所在的子目录。点击“创建项目”按钮,创建包含 2 个文件的文件夹:
- 项目文件: corona-app。Rproj (可能有另一个名字)
- 一个我们不需要的 app 模板文件: app。R
使用 Shiny 创建用户界面
闪亮的框架允许 R 用户用最少的编码工作创建反应式 web 应用程序。小 app 只需要 2 个文件: ui。R 为用户界面布局,而为服务器。R 用于服务器和渲染逻辑。
转到 RStudio 。在用户界面的左上方,有一个创建新文件的加号按钮。点击它,并选择“R 脚本”。创建一个文件,并将其命名为" ui。R "通过保存它,并开始编辑。
首先加载我们需要的包:
library(shiny)
library(plotly)
然后,使用 bootstrap 方案建立一个空白页面(每行 12 列),并使用元素 titlePanel 创建标题:
shinyUI(fluidPage(
titlePanel("Case History of the Coronavirus (COVID-19)"),
))
总之,屏幕被分成不同的行(fluid rows)。带控件的流体行由三个宽度为 4 的列组成,加起来又是 12。地块占据整个宽度(12):

现在添加控件的代码。在定义标题面板的行之后立即插入以下代码(在两个右括号之前!):
fluidRow(
column(
width=4,
selectizeInput(
"country", label=h5("Country"), choices=NULL, width="100%")
),
column(
width=4,
selectizeInput(
"state", label=h5("State"), choices=NULL, width="100%")
),
column(
width=4,
checkboxGroupInput(
"metrics", label=h5("Selected Metrics"),
choices=c("Confirmed", "Deaths", "Recovered"),
selected=c("Confirmed", "Deaths", "Recovered"),
width="100%")
)
),
如您所见,有一个流体行有 3 个列元素,每个元素的宽度为 4。前两列包含下拉菜单元素( selectizeInput ),让用户选择国家和州。
第三列包含一组复选框元素( checkboxGroupInput )。这允许用户选择在两个图中显示哪些指标。
对于这两个图,我们使用 R 包 plotly ( 文档)。以下代码行在接下来的两个流体行中各添加一个 plotly 样式的绘图:
fluidRow(
plotlyOutput("dailyMetrics")
),
fluidRow(
plotlyOutput("cumulatedMetrics")
)
添加加载和预处理数据的逻辑
该应用程序需要一些逻辑来下载和解析数据。这发生在服务器上。再次创建一个新文件,并将其命名为" server。R 并添加这些行来加载各自的 R 包:
library(dplyr)
library(tidyr)
然后定义一个 baseURL ,我们从其中按国家和地区下载冠状病毒的病例数据。数据位于约翰霍普金斯系统科学与工程中心(JHU/CSSE) 的服务器上。此外,定义一个稍后使用的字体( f1 ),加上一个测量文件有多长时间的速记函数(以避免过多的重新加载):
baseURL = "[https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series](https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series)"f1 = list(family="Courier New, monospace", size=12,
color="rgb(30,30,30)")minutesSinceLastUpdate = function(fileName) {
(as.numeric(as.POSIXlt(Sys.time())) -
as.numeric(file.info(fileName)$ctime)) / 60
}
现在,定义主函数来加载特定数据集(例如,按日期和国家列出的确诊病例数)。
loadData = function(fileName, columnName) {
if(!file.exists(fileName) ||
minutesSinceLastUpdate(fileName) > 10) {
data = read.csv(file.path(baseURL, fileName),
check.names=FALSE, stringsAsFactors=FALSE) %>%
select(-Lat, -Long) %>%
pivot_longer(-(1:2), names_to="date", values_to=columnName)%>%
mutate(
date=as.Date(date, format="%m/%d/%y"),
`Province/State`=
if_else(`Province/State` == "", "<all>", `Province/State`)
)
save(data, file=fileName)
} else {
load(file=fileName)
}
return(data)
}
该函数首先检查数据是否已经可用,并且不超过 10 分钟。如果不是这样, read.csv 从网络上下载文件。地理坐标被省略,然后 pivot_longer (来自包 tidyr )将 data.frame 从宽格式转换为长格式。方法 mutate 解析日期并插入文本 < all > 如果没有可用的地区(适用于美国、加拿大、中国和澳大利亚以外的国家)。
下一个块在应用程序启动时立即被调用。如上所述,它从 web 或缓存加载数据:
allData =
loadData(
"time_series_covid19_confirmed_global.csv", "CumConfirmed") %>%
inner_join(loadData(
"time_series_covid19_deaths_global.csv", "CumDeaths")) %>%
inner_join(loadData(
"time_series_covid19_recovered_global.csv","CumRecovered"))
代码块加载确诊病例、恢复病例和死亡病例,并连接这 3 个数据集以获得一个大数据集。
更新[2020-3-27]:文件名已更改,以反映约翰霍普金斯大学的新数据结构(见链接)。
添加服务器逻辑
最后一节介绍了服务器上的静态代码。现在开始主要部分,即反应式服务器代码。本节中添加的所有代码都位于服务器函数的括号内:
server = function(input, output, session) {
## ...
}
数据
首先让我们添加一个反应函数,它返回全部数据的一个子集,即只返回一个指定的国家和地区。每当用户更改选择时,都会调用该函数并更新过滤器:
data = reactive({
d = allData %>%
filter(`Country/Region` == input$country)
if(input$state != "<all>") {
d = d %>%
filter(`Province/State` == input$state)
} else {
d = d %>%
group_by(date) %>%
summarise_if(is.numeric, sum, na.rm=TRUE)
}
d %>%
mutate(
dateStr = format(date, format="%b %d, %Y"),
NewConfirmed=CumConfirmed - lag(CumConfirmed, default=0),
NewRecovered=CumRecovered - lag(CumRecovered, default=0),
NewDeaths=CumDeaths - lag(CumDeaths, default=0)
)
})
此外,如果用户为有州的国家(如美国)选择 <【所有> ,则该函数会汇总数据(使用summary _ if)。此外,根据累积的统计数据,计算差异并保存到新列中,以“New”为前缀。
下拉菜单
接下来,服务器观察国家选择的变化。如果发生这种情况,服务器必须更新可选状态。另外,<>全部作为选项添加到状态下拉菜单中:
observeEvent(input$country, {
states = allData %>%
filter(`Country/Region` == input$country) %>%
pull(`Province/State`)
states = c("<all>", sort(unique(states)))
updateSelectInput(session, "state", choices=states,
selected=states[1])
})
接下来的两行没有反应。相反,它们在应用程序启动时被调用。第一行按字典顺序提取所有国家。另一行在下拉菜单中选择意大利( selectizeInput ):
countries = sort(unique(allData$`Country/Region`))
updateSelectInput(session, "country", choices=countries,
selected="Italy")
情节
对于情节,我们使用了 R 包的条形图。以下代码定义了用于两个图(新的和累积的情况)的函数。该函数的第一部分定义了条形图的基础(样式、轴、图例)。第二部分遍历选定的指标(如恢复的指标等)并添加条形。使用var prefix(“New”或“ Cum ”)和 metric )的列名的组成有点复杂。
*renderBarPlot = function(varPrefix, legendPrefix, yaxisTitle) {
renderPlotly({
data = data()
plt = data %>%
plot_ly() %>%
config(displayModeBar=FALSE) %>%
layout(
barmode='group',
xaxis=list(
title="", tickangle=-90, type='category',
ticktext=as.list(data$dateStr),
tickvals=as.list(data$date)),
yaxis=list(title=yaxisTitle),
legend=list(x=0.1, y=0.9,bgcolor='rgba(240,240,240,0.5)'),
font=f1
)
for(metric in input$metrics)
plt = plt %>%
add_trace(
x=~date, y=data[[paste0(varPrefix, metric)]],type='bar',
name=paste(legendPrefix, metric, "Cases"),
marker=list(
color=switch(metric,
Deaths='rgb(200,30,30)',
Recovered='rgb(30,200,30)',
Confirmed='rgb(100,140,240)'),
line=list(color='rgb(8,48,107)', width=1.0)
)
)
plt
})
}*
最后几行代码使用前面定义的函数。这两个图通过以下方式分配给用户界面元素:
*output$dailyMetrics = renderBarPlot(
"New", legendPrefix="New", yaxisTitle="New Cases per Day") output$cumulatedMetrics = renderBarPlot(
"Cum", legendPrefix="Cumulated", yaxisTitle="Cumulated Cases")*
瞧啊。
这就是全部,你可以通过点击编辑器窗口右上角的“运行应用”按钮来运行代码。
GITHUB 代码
以上所有代码都可以在 GitHub 上找到。毕竟,它只有两个文件,加上项目文件:
https://github.com/ploner/coronavirus-r
[可选]将应用程序上传到云
将闪亮的应用程序发布到 web 服务器的最简单方法是使用 shinyapps 。在 shinyapps 上创建账户后,进入 RStudio,点击右上角的发布图标,然后点击“发布应用程序…”:

用你的账号连接,然后选择你需要的文件(仅限 ui。R 和服务器。R* !)😗

就是这样!你的应用程序运行在网络服务器上,你可以通过互联网访问它。
[2020 年 3 月 19 日更新]有一篇后续文章是关于同一个用例的。相反,如果 R + Shiny + Plotly,它会通过基于 Python 的堆栈:
Python + Dash + Plotly
我叫梅哈德·普洛纳。我对统计学和数据科学并不陌生,但这是我第一篇关于媒体的文章。我希望你喜欢阅读它,并欢迎任何反馈。
更多 R 在行动的例子,查看R-bloggers。
360 万个点,1 个 GIF —用 Python 可视化大数据
使用 Dask 和 Datashader 库用 Python 创建大数据 GIF 的详细分步指南。

纽约市从 1989 年到 2019 年每年提交的建筑许可证。图片作者。
你好!本文将带您一步一步地创建 GIF 来可视化 Python 中的大数据。gif 是显示随时间变化的好方法,尤其是对于大型数据集。本文使用了过去 30 年纽约市建筑许可证,由建筑部门发布,摘自纽约市开放数据。这张 GIF 是我和我的好朋友雅普·云起于 2019 年秋天在纽约市进行的项目的一部分。
IPython 笔记本和环境文件可以在这里找到:【https://github.com/LeanneChan/create-a-GIF】T4。要下载笔记本并用 Jupyter Notebook 打开,可以关注我的另一篇文章这里。您也可以在 GoogleColab 中运行代码,但是根据过去的经验,在 GoogleColab 中加载 geopandas 库需要额外的步骤。
方法
GIF 是拼接在一起的图像集合。因此,我们创建 GIF 的方法是为每个不同的时间框架(在本例中为几年)创建单独的图,然后将它们拼接在一起。如果我们的数据集足够小,我们可以使用 matplotlib 来绘制这些点。但是,对于更大的数据集,我们将使用 Datashader ,一个用于可视化大数据集的库。为了处理大型数据集,我们将使用 Dask ,这是一个 Python 中灵活的并行计算库。
数据着色器
Datashader 是 HoloViz 家族的一部分(其他包包括 HoloViews、hvPlot),用于创建大型数据集的表示。它能够通过光栅化(将一个图分成像素)绘图区域并聚集落在每个像素中的点的值来可视化大型数据集。然后根据该聚合值对像素进行着色。
达斯克
Dask 允许我们存储比笔记本电脑内存还大的数据。此外,Dask 使用起来不会太吓人,因为 Dask 数据帧镜像 Pandas,Dask 数组镜像 NumPy。Dask 将作为 Pandas DataFrame 对象的分区分开,只在必要时将数据加载到我们的计算机内存中。
所需的库
dask、datashader、colorcet、matplotlib、numpy、imageio、geopandas
我们开始吧!
步骤 1:加载施工许可数据
数据集具有 shape (3616003,60),这意味着有 60 个列/要素和 360 万行/点。这是一个地理空间数据集和可视化,所以每一行代表纽约市的一个点,这是我们想要绘制的。由于有 3.6M 行,我们将需要 dask.dataframe 库。import用于将库中的库加载到你当前的工作区/会话中,这允许我们使用库中的方法。
import dask.dataframe as dd
如果你以前用过 pandas,语法真的很类似,调用read_csv读入 dataframe,我从 NYC open data 下载的,保存在我 Jupyter 笔记本的同一个文件夹里,名为‘DOB _ permit _ issuement . CSV’。
permits = dd.read_csv(‘./data/DOB_Permit_Issuance.csv’) permits.head()
然而,如果您得到下面的错误,您也将需要寻址具有混合类型的列。

未指定某些列的数据类型时的错误。图片作者。
在这个例子中,我必须为某些列指定dtype,因为它们具有混合类型,这在尝试调用 dataframe 时会引发错误。dtype 指定了列中数据的格式,因此当 pandas/dask 不得不猜测太多的列类型时会出现错误。我还使用usecols只选择了三列,而不是 60 列,以使未来的过程更快。这些栏显示了许可证提交的日期(以便以后提取年份)和许可证的 lat/lng。解决“混合数据类型”问题的另一种方法是只选择有用的、没有混合数据类型的列。事后看来,这是我本可以做的事,以节省自己很多时间!
permits = dd.read_csv('./data/DOB_Permit_Issuance.csv',
dtype={
'Lot': 'int64',
'Block': 'int64',
"Owner's Phone # ": 'float64',
"Owner’s House Zip Code": 'float64',
"Permittee's License #": 'float64',
"Zip Code":'int64'
},
usecols=['Filing Date', 'LATITUDE', 'LONGITUDE'])
显示我们数据帧的前 5 行。(仅供参考,调用dataframe.head(x),其中 x 是任意整数,将打印出数据帧的前 x 行!)

这是我们将使用的数据帧的前 5 行。图片作者。
第二步:数据准备
首先是,我们要提取每个许可证的年份。我使用了熊猫函数to_datetime(),将“提交日期”列转换为日期-时间对象。由于该列现在是一个 datetime 对象,我可以使用另一个函数.dt.strftime(“%Y”)来访问每个点的年份以创建一个新列。
# change the column type
permits['Filing Date'] = dd.to_datetime(permits['Filing Date'])# create new column for the year
permits=permits.assign(year= permits['Filing Date'].dt.strftime("%Y"))
其次,我们需要为我们的坐标决定一个标准化的投影。这是地理空间数据科学中非常重要的一点,因为如果你的底图和你的点在不同的投影和坐标系中,混乱就会随之而来。一个坐标参考系统(CRS) ,是一个代码(epsg 代码),指的是空间数据(本来就是圆的,因为扁平的地球是一个骗局)如何被投影到一个扁平的 2D 屏幕上。它还指定了测量单位,通常是英尺、米或十进制度。

来源:earth data science . org:https://www . earth data science . org/courses/earth-analytics/spatial-data-r/intro-to-coordinate-reference-systems/
对于这个例子,我使用了 Web-Mercator 投影(epsg: 3857),基于米的投影。虽然在本例中没有这样做,但如果您想使用 OpenStreetMap 或 GoogleMaps 中的底图,这种投影特别有用,因为它们采用 epsg:3857 投影。Datashader 有一个很有用的函数lnglat_to_meters,可以将经度和纬度(epsg:4326,十进制度数)转换为 web-mercator(米)。确保您知道转换后哪个是您的 lat 和 lng,并按照每个函数中要求的正确顺序对它们进行编码,这一点非常重要。
# conversion to web mercator
from datashader.utils import lnglat_to_meters# create new columns 'x' (longitude) and 'y' (latitude)
permits['x'], permits['y'] = lnglat_to_meters(permits['LONGITUDE'], permits['LATITUDE'])# keep a clean dataframe
permits = permits.drop(['LONGITUDE', 'LATITUDE'], axis=1)
步骤 3:实施 Dask 最佳实践
我们遵循一些 Dask 最佳实践,将索引设置为我们想要按年份分组的列。尽管使用set_index需要大约 8 分钟,这使得稍后的子集设置快了 100 倍(0.001 秒!).
# set index so that it is arranged by year
# drop na, if not will not be able to set index
permits = permits.dropna() # dataframe will be arranged by year
permits_indexed = permits.set_index('year')
# set_index takes about 8-9 minutes
分区: Dask 通过将大型数据集分割成分区来运行。提到的最佳实践之一是根据您感兴趣的子集(在我们的例子中是年)来设置您的分区。
# create list of strings of years
dateRange = list(range(1989,2020))
years = []for year in dateRange:
str_year = str(year)
years.append(str_year)# repartition the data - takes 0.001 seconds
permits_repartitioned = permits_indexed.repartition(divisions=years)
Compute: .compute()在我们的 Dask 数据帧上执行所有上述过程,并返回一个普通的数据帧。这样做会大大增加创建 GIF 所需的时间。如果此处没有调用compute(),上述所有数据争论将在 dataframe 的每次调用中重新计算,每帧耗时 10 分钟。那就是 30 帧的 300 分钟!
permits_computed = permits_repartitioned.compute()
这需要 9 分钟,但是如上所述,为我们节省了更多的时间。
步骤 4:设置绘图边界
从一开始的示例 GIF 开始,这些地块包括纽约市各区的轮廓——曼哈顿、布鲁克林、皇后区、布朗克斯和斯塔滕岛。我从纽约开放数据下载了形状文件‘行政区边界’。我们将需要geopandas库来读取 shapefile。不要忘记将 CRS 设置为与您在步骤 2 中用于数据点的 CRS 相同。
# add NYC borough boundaries (coords must be in 3857)import geopandas as gpd
NYCBoroughs= gpd.read_file("./data/borough boundaries")
NYCBoroughs = NYCBoroughs.to_crs({'init': 'epsg:3857'})

纽约市行政区的形状。截图自 NYC 公开资料:https://Data . cityofnewyork . us/City-Government/Borough-Boundaries/tqmj-j8zm。
由于我们希望地块也能完美地围绕城市,我们需要将地块上 x 和 y 坐标的范围设置为纽约市的界限,这是我从 GoogleMaps 中的拖放点获得的。再一次,不忘把坐标转换成 epsg: 3857。至于绘图尺寸,我建议你先摆弄那些图形,然后在画布上绘图(见下一节),看看什么最适合你。
# NYC limits - lng(east/west) and lat(north/south)
NYC = (( -74.25, -73.7), (40.50, 40.92))
x_range, y_range = [list(r) for r in lnglat_to_meters(NYC[0], NYC[1])]# plot dimensions
plot_width = int(750)
plot_height = int(plot_width//1.2)
步骤 5:创建图像
至此,我们已经拥有了制作 GIF 所需的所有部分,我们只需要把它们放在一起!首先,我们需要导入一些库来帮助我们绘图。正如在“方法”中提到的,我们将在绘图前使用 datashader 来聚合点。我们不只是想要地图上的点,而是让地图告诉我们哪里有更高频率的点。Datashader 将在此基础上帮助我们给点着色。
# plotting functions
from colorcet import fire
import datashader as ds
import datashader.transfer_functions as tf
让我们创建一个助手函数来绘制施工许可证,我们可以在以后绘制每年的不同点时使用它。
该函数接受参数: df —数据,
x_range,y_range—底座上 x/y 坐标的范围(见步骤 3),
w/h —绘图的宽度和高度(见步骤 3),
cmap —用于给点着色的彩色地图。
def create_image(df, x_range, y_range, w=plot_width, h=plot_height, cmap=fire):
# create the canvas
cvs = ds.Canvas(plot_width=w, plot_height=h, x_range=x_range, y_range=y_range)
# the construction permits, aggregated by their count
agg = cvs.points(df, 'x', 'y')
# shade the pixels
img = tf.shade(agg, cmap=cmap, how='eq_hist')
# return a PIL image
return tf.set_background(img, "black").to_pil()
该函数使用 datashader 的 canvas 函数来表示我们要在其中绘制点的空间。首先,我们创建画布,指定尺寸。接下来,我们使用cvs.points()输入数据,它接收数据,‘x’—转换后的经度,和‘y’—转换后的纬度。cvs是在第一行创建的画布对象。
聚合数据 您可以在cvs.points()中指定的另一个参数是agg,它将通知 datashader 如何聚合您的数据。假设你有一个名为“z”的第三列,如果你想在这个聚合空间中绘制 z 的平均值,你可以包括agg=ds.mean('z')。如果没有指定,agg的缺省值是‘count ’,这是我们在这个例子中想要的,因此没有指定。
最后,datashader.transfer_functions.shade指定如何给每个像素着色。我们使用的色图是火,来自colorcet库。how指定颜色图的比例。一些选项包括:' eq _ hist '[默认值],' cbrt '(立方根),' log '(对数)和'线性'。有关更多信息,请参见结尾链接的 datashader 文档。然后,我们将背景指定为黑色,并将图像转换为 Python 图像库(PIL)格式。
步骤 6:每年绘图的函数
我们快完成了!我们不想为每个时间帧手动创建新图像,所以我们将其打包在另一个函数中。对于这个函数,我们将需要 matplotlib 的 pyplot 来设置轴,并需要 numpy 来将图形值转换到范围 0–255(dtype = uint 8)以创建最终的图像。
from matplotlib import pyplot as plt
import numpy as np
该函数接受参数: fig—来自 pyplot,
all_data —我们的数据框架,
year —要绘制的具体年份,
city_limits —要绘制的边界的 shapefile,
x_range,y_range —基底上 x/y 坐标的范围(见步骤 3)。
def plot_permits_by_year(fig, all_data, year, city_limits, x_range, y_range): # trim to the specific year
df_this_year = all_data.loc[year] # create the datashaded image
img = create_image(df_this_year, x_range, y_range) # plot the image on a matplotlib axes
plt.clf() # this clears current figure
ax = fig.gca() # this gets the axes from fig
ax.imshow(img, extent=[x_range[0], x_range[1], y_range[0], y_range[1]]) # show the image on the axes
ax.set_axis_off()
# plot the city limits (NYC borough boundaries)
city_limits.plot(ax=ax, facecolor="none", edgecolor="white") # add a text label for the year
ax.text(
0.0,
0.9,
"Yearly Construction Permits\nFiled in NYC",
color="white",
fontsize=20,
ha="left",
transform=ax.transAxes,
) ax.text(
0.7,
0.1,
year,
color="white",
fontsize=40,
ha="left",
transform=ax.transAxes,
) # draw the figure and return the image
fig.canvas.draw()
image = np.frombuffer(fig.canvas.tostring_rgb(), dtype="uint8")
image = image.reshape(fig.canvas.get_width_height()[::-1] + (3,)) return image
使用loc对我们的数据进行子集划分只需要 0.001 秒。
该函数还指定要在每一帧上显示的文本,这是使用 matplotlib 函数ax.text()完成的,其中ax指的是图像的轴。
第七步:把图片做成 GIF!
我们就在最后,我们只需要使用imageio库将图像数组转换成 gif。为了创建 GIF,我们使用步骤 5 中的函数创建图像,将它们附加到一个数组中,然后使用image.io将它们拼接成一个 GIF。
# library to create GIF
import imageio
运行下面的块代码来创建完整的 GIF!如果您对设计不满意,请在步骤 5 的功能中更改参数(如标签的位置/颜色/尺寸)。(参见 matplotlib 文档)
注:‘years’数组是在第 3 步分区过程中创建的。
# create a figure
fig, ax = plt.subplots(figsize=(10,10), facecolor='black')# Create an image for each hour
imgs = []
for year in years:
print('processing ' + year + ' ...')
img = plot_permits_by_year(fig, permits_computed, year, NYCBoroughs, x_range=x_range, y_range=y_range)
imgs.append(img)
# Combining the images for each hour into a single GIF
imageio.mimsave('1989_2019_permits.gif', imgs, fps=1)
这段创建 30 帧的代码块仅用了 9.56463 秒运行!
就是这样!谢谢你的关注,如果我能澄清什么,请告诉我!
过去的编辑和关于时间复杂性的附加信息 2020 年 5 月 30 日 —更改流程以加快子集设置,并调用.compute()以减少 Dask 操作。(当前文章反映了正确的代码。)
在初始过程中(代码不再显示),我跳过了第 3 步,在 plot_by_year 函数中设置了数据帧的子集。因此,打印每年的框架大约需要 10 分钟。这也是因为由于 Dask 的性质,每次调用 dataframe 时,数据集上的数据争论都会重复。我的直觉是,在每次调用 plot_by_year 函数时,必须再次执行将坐标转换为墨卡托坐标、转换“归档日期”列和设置数据框子集的过程。在 Dask 数据帧上调用compute()解决了这个重复问题。
为了检查花费的时间,我使用了time图书馆。
子集花费的时间:旧方法
start=time.time()
df_this_year = permits.loc[permits["Filing Date"].dt.strftime("%Y") == '2009'].compute()
print(time.time()-start)# 616.4123058319092 seconds
子集花费的时间:新方法
start = time.time()
permits_2009 = computed_repartitioned.loc['2009']
print(time.time()-start)# 0.0010952949523925781 seconds
这个新过程是对我花了几个小时创建 GIF 的原始代码的巨大改进!感谢 @james.a.bednar 为改进原代码所做的小小额外推动!
致谢: Nicholas Hand,MUSA 620 教授,他教会了我大部分的 python 数据可视化技巧!
数据来源: 建筑许可证,纽约市公开数据,建筑署https://Data . cityofnewyork . us/Housing-Development/DOB-Permit-issued/IPU 4-2q9a
纽约市行政区边界,纽约市公开数据,城市规划部https://Data . cityofnewyork . us/City-Government/Borough-Boundaries/tqmj-j8zm
Datashader 文档:https://readthedocs . org/projects/data shader/downloads/pdf/stable/
使用 SQL 通过 Google Cloud BigQuery ML 创建机器学习模型

我的简单白板
随着机器学习模型在不同领域的应用,以及技术的进步(更好的硬件和高级编程语言),建立一个适合您需求的工作机器学习模型变得越来越容易。制作机器学习模型的过程越来越简单,代码行数越来越少。
在本文中,我将向您展示如何使用 Google BigQuery ML 构建一个只包含 SQL 的定制 ML 模型。
但是首先,Google BigQuery 是什么?
Google BigQuery 是一个无服务器、低成本、高可伸缩的数据仓库系统,由 Google Cloud Platform 提供,具有许多业务敏捷性特性。BigQuery ML 就是这样一个特性,它帮助数据科学家、数据分析师和数据工程师(比如我)构建可操作的生产级 ML 模型。我们可以在结构化和非结构化数据上创建模型。最重要的是,只需在短时间内使用 SQL 环境进行查询。
在本文中,我们将完成以下任务:
- 使用“德国信用数据”作为样本数据集来预测贷款申请的好坏。
- 将样本数据分为训练集和测试集。
- 创建并加载 Google BigQuery 表中的数据。
- 只需使用 SQL 创建一个“逻辑回归”模型。
- 最后,我们将评估和预测贷款类型的好坏。
我们将使用的样本数据:
我们将使用一个样本结构化数据集“德国信贷数据”。您也可以从下面的 git 资源库下载这些文件:
https://github . com/aa kash-ra thore/BigQueryML/tree/master/data
├── data
│ ├── germanCredit.csv
│ ├── GermanCredit.xls
│ ├── testData.csv
│ └── trainData.csv
├── README.md
└── test_train.py
在存储库“GermanCredit.xls”的原始数据文件中,该文件提供了所有列数据的详细信息。我已经对所有分类数据进行了编码,并创建了一个文件“german credit . CSV”,“test _ train . py”是一个 python 脚本,用于将数据划分到测试和训练数据集中(testData.csv 和 trainData.csv)
在 BigQuery 中加载数据:
登录到 Google 云平台控制台,使用左侧选项面板导航到 BigQuery 选项卡。

在 GCP 控制台中选择 Bigquery 工具
使用 BigQuery 控制台中的选项创建数据集。

创建数据集
从先前创建的数据集中的 trainData.csv 和 testData.csv 创建表格。

创建包含列车数据的表创建包含测试数据的表
在选择相应的表后,我们可以使用“预览”选项预览创建的表中的样本数据。

预览表格数据
现在,我们可以开始创建一个 ML 模型,在我们的样本数据中,“响应”列是结果标签(1 =好,0 =坏),其他列是输入特征。令人惊奇的是,我们将只使用 SQL 查询来创建和评估我们的 ML 模型。
创建 ML 模型:
我们将创建一个逻辑回归模型,这是一个分类模型,在我们的案例中,我们将使用它来根据以前的信用报告数据对贷款申请进行分类。
SQL 查询创建一个 ML 模型:
# Creating logistic regression model using data from trainData tableCREATE OR REPLACE MODEL
`mltestDataset.credit_classification_model` OPTIONS ( model_type='logistic_reg' labels=['response'] ) AS
SELECT
* EXCEPT(obs)
FROM
`mltestDataset.trainData`

从包含训练数据的表中创建模式
评估创建的 ML 模型:
评估 ML 模型有不同性能参数,在我们创建的 ML 模型中,当评估我们训练的 ML 模型时,roc_auc 是这样一个简单的可查询字段。
评估 ML 模型的 SQL 查询:
# Evaluating logistic regression model using data from testData tableSELECT
roc_auc,
CASE
WHEN roc_auc > .8 THEN 'good'
WHEN roc_auc > .7 THEN 'fair'
WHEN roc_auc > .6 THEN 'not great'
ELSE
'poor'
END
AS model_quality
FROM
ML.EVALUATE(MODEL mltestDataset.credit_classification_model,
(
SELECT
* EXCEPT(obs)
FROM
`mltestDataset.testData` ) )
输出:

使用曲线下的 ROC 面积评估模型性能
正如您可以看到的性能相当不错,我们可以通过使用特征工程调整模型来提高性能。但是为了简单起见,我们将使用这个模型来分析预测。
预测使用创建的 ML 模型:
现在我们将使用这个模型来预测贷款类型(1 =好,0 =坏)。下面给出了从模型中获取预测的查询:
# Getting prediction for our ML model using data from testData tableSELECT
*
FROM
ml.PREDICT(MODEL `mltestDataset.credit_classification_model`,
(
SELECT
* EXCEPT(obs)
FROM
`mltestDataset.testData` ) );
输出:
我们将检查前 5 个预测:

检查预测
我们可以看到前 5 个预测的结果:
1。对于第一条记录,我们的模型以 84%的置信度预测贷款是好的(响应=1),实际上,它是好的(响应=1)。
2。对于第二条记录,模型以 93%的置信度预测贷款是好的(响应=1),实际上,它是好的(响应=1)。
3。对于第三条记录,模型以 63%的置信度预测贷款是好的(响应=1),实际上,它是好的(响应=1)。
4。对于第 4 条记录,模型以 74%的置信度预测贷款是好的(响应=1),实际上,它是好的(响应=1)。
5。对于第 5 条记录,模型以 66%的置信度预测贷款为不良贷款(响应=0),实际上,它是不良贷款(响应=0)。
结论:
在本文中,我解释了如何使用 SQL 在 Google BigQuery 中创建和评估 ML 模型。后来我们分析了这个模型的预测。
请在下面留下您对本文的评论,如果您在上面指定的任何步骤中遇到问题,您可以通过insta gram**和 LinkedIn 联系我。**
使用 Azure 自定义视觉和 Python 创建模型
在这篇文章中,我想和你分享如何使用 Azure Custom Vision 和 Python SDK 创建一个分类模型。
为什么是 Python 而不是可视化界面?
答案很简单,如果你用代码构建训练过程,你可以在 Github 上对它进行版本化。让你的代码版本化意味着你可以回读你所做的,在一个团队中工作,如果你需要的话再运行一次。
让我们深入研究代码!在我们开始之前,我假设你已经安装了 Python 3.6 。
在 Azure 中创建资源
您需要做的第一件事是创建一个 Azure 自定义视觉服务。如果你没有 Azure 套餐,你可以在第一个月获得 200 美元的点数。
您可以通过门户轻松创建 Azure 自定义 Vision 端点,但您也可以为此使用 Azure CLI 。如果你没有安装 Azure cli,你可以使用 pip 来安装。
pip install azure-cli
第一步是登录到您的 Azure 订阅,选择正确的订阅并为自定义 Vision 端点创建资源组。
az login az account set -s <SUBSCRIPTION_ID> az group create --name CustomVision_Demo-RG --location westeurope
自定义视觉服务有两种类型的端点。一个用于训练模型,另一个用于针对模型运行预测。
让我们创建两个端点。
az cognitiveservices account create --name CustomVisionDemo-Prediction --resource-group CustomVision_Demo-RG --kind CustomVision.Prediction --sku S0 --location westeurope –yes az cognitiveservices account create --name CustomVisionDemo-Training --resource-group CustomVision_Demo-RG --kind CustomVision.Training --sku S0 --location westeurope –yes
现在我们已经创建了端点,我们可以开始训练模型了。
一切都从一个问题开始

每一次机器学习之旅都是从一个你希望得到答案的问题开始的。在这个例子中,你要回答这个问题:它是一个荷马还是一个玛吉·乐高玩具?
既然我们知道了要问模型什么,我们可以继续下一个需求;那就是数据。我们的模型将是一个分类模型,这意味着模型将查看图片,并根据不同的类别对图片进行评分。因此,输出将是我 70%确信这是荷马,1%确信这是玛吉。通过选择得分最高的班级,并为置信度设置一个最低阈值,我们就知道图片上是什么了。
我已经为你创建了一个数据集,其中有 50 张荷马·辛普森乐高玩具的图片和 50 张玛吉·辛普森乐高玩具的图片。我拍摄这些照片时考虑了一些事情,使用了很多不同的背景,从不同的角度拍摄了这些照片。我确保照片中唯一的物体是荷马或玛吉,并且照片的质量在某种程度上是一致的。
训练模型
对于培训,我们将使用定制视觉服务 Python SDK ,您可以使用 pip 安装这个包。
pip install azure-cognitiveservices-vision-customvision
创建一个名为“train.py”的新 Python 文件,并开始添加代码。
从导入所需的包开始。
from azure.cognitiveservices.vision.customvision.training import CustomVisionTrainingClient
from azure.cognitiveservices.vision.customvision.training.models import ImageFileCreateEntry
接下来,为自定义视觉端点、自定义视觉训练密钥和存储训练图像的位置创建变量。
cv_endpoint = "https://westeurope.api.cognitive.microsoft.com" training_key = "<INSERT TRAINING KEY>"
training_images = "LegoSimpsons/TrainingImages"
从培训开始,我们需要创建一个培训客户端。该方法将端点和训练密钥作为输入。
trainer = CustomVisionTrainingClient(training_key, endpoint= cv_endpoint)
现在您已经准备好创建您的第一个项目了。该项目以名称和域作为输入,名称可以是任何东西。领域是一个不同的故事。你可以要求列出所有可能的领域,并选择最接近你要完成的领域。例如,如果你试图对食物进行分类,你可以选择“食物”或“地标”作为地标。使用下面的代码显示所有域。
for domain in trainer.get_domains():
print(domain.id, "\t", domain.name)
您可能会注意到,一些域旁边有单词“Compact”。如果是这种情况,这意味着 Azure Custom Vision 服务将创建一个较小的模型,您可以导出该模型并在您的手机或桌面上本地运行。
让我们创建一个域设置为“General Compact”的新项目。
project = trainer.create_project("Lego - Simpsons - v1","0732100f-1a38-4e49-a514-c9b44c697ab5")
接下来你需要创建标签,这些标签和上面提到的类是一样的。当您创建了一些标签后,我们可以用它们来标记图像,并将图像上传到 Azure Custom Vision 服务。
我们的图像在文件夹中按标签/类别分类。玛吉的所有照片都在名为“玛吉”的文件夹中,荷马的所有照片都在名为“荷马”的文件夹中。
在下面的代码中,我们执行以下步骤:
- 我们打开包含训练图像文件夹的目录。
- 遍历在该文件夹中找到的所有目录
- 用文件夹名称创建一个新标签
- 打开包含图像的文件夹
- 为该文件夹中的每个图像创建一个包含文件名、文件内容和标签的 ImageFileEntry。
- 将此 ImageFileEntry 添加到列表中。
image_list = []
directories = os.listdir(training_images)for tagName in directories:
tag = trainer.create_tag(project.id, tagName)
images = os.listdir(os.path.join(training_images,tagName))
for img in images:
with open(os.path.join(training_images,tagName,img), "rb") as image_contents:
image_list.append(ImageFileCreateEntry(name=img, contents=image_contents.read(), tag_ids=[tag.id]))
现在您有了一个包含所有标记图像的列表。到目前为止,Azure Custom Vision 服务中还没有添加任何图像,只创建了标签。
上传图片分批进行,每批最多 64 张图片。我们的数据集有 100 张图片,所以首先我们需要将列表分成 64 张图片。
def chunks(l, n):
for i in range(0, len(l), n):
yield l[i:i + n]
batchedImages = chunks(image_list, 64)
现在,我们已经将图像分成 64 个一批,我们可以将它们一批一批地上传到 Azure Custom Vision 服务。注意:这可能需要一段时间!
for batchOfImages in batchedImages:
upload_result = trainer.create_images_from_files(project.id, images=batchOfImages)
现在您已经到达了最后一步,我们可以发布模型了。然后,它在预测 API 中可用,并准备好供应用程序使用。
每次训练你的模型都被称为一次迭代。当你有了新的数据,或者当你发现在现实世界中你的模型与预期的有所不同时,你通常需要重新训练你的模型。
Custom Vision 服务的概念是,您可以在特定的名称下发布模型的迭代。这意味着您可以有多个版本的模型供您的应用程序使用,例如,您可以用它非常快速地对您的模型进行 a-b 测试。
要发布模型的迭代,您需要调用 publish_iteration 方法,该方法需要几个参数。
项目 ID 和迭代 ID,这些是来自前面步骤的值。您可以为模型的发布选择一个名称,例如“最新”或“版本 1”。您需要的最后一个参数是您要将它发布到的资源的“资源标识符”。这是我们在开始时用 AZ 命令创建的 Azure 自定义视觉预测资源的资源标识符。
您可以使用此命令检索您创建的预测资源的所有详细信息:
az cognitiveservices account show --name CustomVisionDemo-Prediction --resource-group CustomVision_Demo-RG
您可以复制字段 ID 后面的值,如下所示:
/subscriptions/<SUBSCRIPTION-ID>/resourceGroups/<RESOURCE_GROUP_NAME>/providers/Microsoft.CognitiveServices/accounts/<RESOURCE_NAME>")
获得资源 ID 后,将其粘贴到下面的变量中,并调用“publish_iteration”方法。
publish_iteration_name = '' resource_identifier = '' trainer.publish_iteration(project.id, iteration.id, publish_iteration_name, resource_identifier)
现在您已经成功地训练并发布了您的模型!
简单回顾一下我们所做的工作:
- 您创建了一个包含 Azure 自定义视觉服务培训和预测端点的 Azure 资源组
- 您已经创建了一个新项目
- 在该项目中,您已经创建了标记
- 您分批上传了 64 张图片,并对其进行了标记
- 您已经训练了模型的迭代
- 您已经将迭代发布到预测端点
我们来测试一下模型!
在应用程序中使用模型就像调用 API 一样简单。您可以只对端点进行 json post,但也可以使用自定义 Vision Python SDK 中的方法,这将使事情变得容易得多。
创建一个名为“predict.py”的新文件
从导入预测所需的依赖项开始。
from azure.cognitiveservices.vision.customvision.prediction import CustomVisionPredictionClient
接下来你需要的是预测键。这是您将模型发布到的资源的键。您可以使用这个 az 命令来列出这些键。
az cognitiveservices account keys list --name CustomVisionDemo-Prediction --resource-group CustomVision_Demo-RG
当您拥有预测键时,您可以创建一个预测客户端。对于这个客户端,您还需要端点。您可以运行下面的 az 命令并复制字段“endpoint”后面的 url。
az cognitiveservices account show --name CustomVisionDemo-Prediction --resource-group CustomVision_Demo-RG
现在您有了预测键和端点,可以创建 PredictionClient 了。
predictor = CustomVisionPredictionClient(prediction_key, endpoint=ENDPOINT)
您有多种选择来对图像进行分类。您可以发送 URL,也可以将二进制图像发送到端点。默认情况下,Azure Custom Vision 服务会保存发布到端点的所有图像的历史记录。可以在门户中查看图像及其预测,并用于重新训练您的模型。但是,有时你不希望图像保留在历史中,因此可以禁用此功能。
我已经上传了两张图片,你可以用来测试,但是你也可以使用搜索引擎找到其他的图片,比如玛吉的图片和 T2 的图片。
要使用 URL 对图像进行分类并保留历史记录,您需要调用“classify_image_url”方法。您可以根据上面的几个步骤为它提供项目 id 和迭代名称,并提供图像的 URL。
results = predictor.classify_image_url(project.id,publish_iteration_name,url="https://missedprints.com/wp-content/uploads/2014/03/marge-simpson-lego-minifig.jpg")
要在屏幕上显示不同类别的分数,您可以使用下面的代码循环显示结果,并显示图像的标签名称和置信度分数。
for prediction in results.predictions:
print("\t" + prediction.tag_name + ": {0:.2f}%".format(prediction.probability * 100))
现在,您已经完成了所有工作,并且拥有了自己的运行在云中的分类模型!以下是您所取得成就的回顾:
- 我们问了一个问题
- 收集的数据
- 创建了 Azure 自定义视觉服务端点
- 创建了新项目
- 标记和上传的内容
- 训练模型
- 发布迭代,以便它可以在 API 中使用
- 使用 API 对模型运行预测
在这一系列文章的其余部分,我们将把这个模型用于不同的解决方案!敬请期待!
资源:
在 Power BI 中创建网络图
数据科学/电力 BI 可视化
点击几下鼠标就能构建网络图的快速入门指南。

艾莉娜·格鲁布尼亚克在 Unsplash 上的照片
在上一篇 的文章 中,我写了一个使用 networkx 和 matplotlib 可视化熊猫数据帧的快速入门指南。虽然学习和探索 Python 中的网络图很有趣,但我开始思考如何向那些机器上没有安装 Python 或 Jupyter Notebook 的人展示结果。在task us,我们在大部分报告中使用 Power BI,因此我开始寻找一种定制的 Power BI 可视化技术,它可以获取数据并将其转换为有意义的网络图。
进入网络导航器。
Network Navigator 是微软创建的 Power BI 中的一个自定义可视化工具。它允许您“通过平移和放大受力控制的节点布局(可以预先计算或实时制作动画)来浏览节点链接数据。”在本帖中,我们将通过使用自定义可视化工具创建网络图所需的步骤。
首先,让我们得到我们的数据。你可以在这里下载样本数据集。然后,我们可以将数据加载到 Power BI Desktop 中,如下所示:

选择文本/CSV 并点击“连接”。

在 Windows 资源管理器文件夹中选择文件,然后单击打开:

点击“转换数据”。

点击“使用第一行作为标题”。

点击“关闭并应用”。

接下来,找到“可视化”面板末端的三个点。

并选择“获得更多视觉效果”。

将鼠标光标指向搜索文本框,输入“网络”,按“回车”键,然后单击“添加”按钮。


稍等片刻,您将看到下面的通知。单击“确定”按钮关闭通知。

你会看到一个新的图标出现在“可视化”面板的底部,如下所示。

点击新图标,你会看到类似下图的东西。

选择新的可视占位符后,单击“Fields”面板中的“Reporter”和“Assignee ”,它会自动将列分配为源节点和目标节点。

让我们通过点击画笔图标来添加标签。

单击“布局”展开该部分,并向下滚动,直到看到“标签”部分。

点击“标签”下的切换开关将其打开

瞧啊。

就是这样!只需点击几下鼠标,我们就能从 csv 文件创建网络图。
我希望你喜欢今天关于 Power BI 最酷的视觉效果之一的帖子。网络图分析是一个大话题,但我希望这个温和的介绍将鼓励你探索更多,扩大你的曲目。
在下一篇文章中,我将分享我从懒鬼到数据科学家的旅程,我希望它能激励其他人,而不是被仇恨者劝阻。
敬请期待!
[1]:商业应用程序—微软应用程序源。(2020 年 5 月 16 日)。网络领航员图表https://app source . Microsoft . com/en-us/product/power-bi-visual s/wa 104380795?src = office&tab = Overview
使用 Dash 和 CSS 引导创建专业仪表板
实践教程
在 Git 和 Heroku 上有一个逐步解释的例子
介绍
在本文中,我将按照我的步骤创建一个交互式仪表板,使用 PlotlyDash,一个 Python 和 R 的库,并使用 CSS Bootstrap 增强布局。
D ash 库基于 Flask、Plotly.js 和 React.js 编写,允许用纯 Python 构建数据可视化应用程序,通过 web 浏览器呈现。
我产生的最终结果可以显示在这里:https://corporate-dash.herokuapp.com/

作者图片
这是一个多页仪表板,模拟一个业务场景,其中通常有一些布局指南要遵守(公司颜色方案、预定义的字体、可以激励我们的公司网站等)和一些与销售相关的 KPI 要监控。
第一页充满了不同类型的图表(散点图、条形图、气泡图、热图)和一个摘要表,带有随机数据;其他页面是空白的,但是对于展示如何构建多页面结构很有用。
在本文中,我将介绍:
1.仪表板目标
仪表板旨在提供一些与业务相关的 KPI 的清晰而准确的视图,使最终用户能够理解所呈现的内容,找到所需的信息,应用一些过滤器,并有希望得出一些结论。
这个仪表板设计得像一个网站,由不同的页面组成,顶部有一个导航条。
每个页面内容分为三个部分:
- 可以应用于页面中显示的所有图表的一些顶级过滤器
- 摘要表也显示在顶部,使用户能够快速浏览主要 KPI。理想情况下,目的是让用户避免浏览页面上的每一个图表,而是通过查看摘要表就能立即发现应该关注的地方。这个摘要表有一些条件颜色格式,就像交通灯一样,突出显示正/负值。
- 最后是一个图表网格,显示了主要 KPI 的不同视图
我有意避免为用户提供任何导出底层数据的方法:由于对数据隐私和数据丢失的担忧日益增加,仪表板只打算使用聚合数据。最终用户无法获得原始数据点。
2.Dash 入门
plotly Dash 有大量的用户指南和介绍。
我个人发现浏览这些资料非常有用,这解释了大量的例子:
- Dash 官方网站https://dash.plotly.com/非常有用,易于阅读和导航,显示所有可用的组件及其主要属性
- 本文从里到外解释了一个非常完整详细的例子:https://towardsdatascience . com/how-to-build-a-complex-reporting-dashboard-using-dash-and-plotl-4f 4257 c 18 a 7 f
- 我还寻找了大量 Youtube 视频,展示如何创建和定制基本的 Dash 布局和回调
尽管查阅了所有这些有用的资料,我不得不面对许多挑战,尤其是为了理解如何按照我想要的方式定制 Dash 组件。
出于这个原因,我也将在下面的步骤中关注这一方面:增强的功能和布局,最终结果的视觉识别是一个非常重要的方面,可以产生影响。
3.为多页仪表板配置文件夹结构
应按照 Dash 指南(【https://dash.plotly.com/urls】T2)的建议构建应用程序源代码文件,以实现多页面导航。基于这个指南,我使用了以下方法来最小化任何代码更改或改编。
我的根文件夹包含:
- app.py :这个文件很基础,只会定义 Flask 需要的 app 变量。我只是简单地遵循 Plotly Dash 指南来创建这个文件。
- index.py :这是一种导航文件,帮助应用程序管理不同页面的 URL。此外,这个文件是非常标准的:我建议遵循 Plotly Dash 指南,因为我们只需要自定义路径名就可以了。
- layouts.py :所有页面 html 布局都将存储在这个文件中。考虑到一些组件(如页眉或导航条)必须在每个页面上重复,我创建了一些函数来返回它们,避免了代码中的重复
- callbacks.py :所有回调(Dash 组件背后的函数,定义用户与图形的交互)都将存储在这个文件中
在根文件夹中,Dash 将查找:
- “数据子文件夹:包含仪表板的底层数据
- 一个“资产”子文件夹:包含附加文件,如:图像;收藏夹图标,供浏览器使用;。css 文件
如果 assets 子文件夹遵循这种结构,应用程序将自动检测并使用 favico.ico 文件或。css 文件,不需要任何代码!只需将图像命名为“favicon.ico ”,并将其放在 root/assets 中,Dash 就会自动使用它。
根文件夹中还有一些附加文件(例如。gitgnore,README.md,Procfile,requirements.txt):在 Heroku 上部署 app 或者在 Git Hub 上存储代码都需要这些文件。
4.用 CSS 引导网格系统概念化布局
有了应用程序文件夹结构,接下来要配置的是页面的整体布局。谈一个 web 应用布局不能不提。css 文件,集中了几乎所有的布局属性,可以被浏览器读取。
用很少的话来说。css 文件定义 html 组件的属性(字体属性、大小、颜色、背景等),Dash 也使用这些属性。
应用程序将开始应用布局属性到相应的 html 组件,从。存储在应用程序的“资产”文件夹中的 css 文件。
需要注意的是:如果同一个 html 组件的属性(例如 H2 html 标题字体系列)在多个。css 文件,应用程序读取的最后一个文件(让我们忽略!重要的 css 后缀)。
CSS 属性也可以通过创建一些自定义的“类”来定义,然后分配给我们想要样式的 html 组件(如 div)。
在我的例子中,我用了 3。css 文件,我用一些前导数字来命名,以确保应用程序以特定的顺序读取它们:
- 自定义字体,定义应用程序使用的新字体系列(你可以从谷歌下载字体系列,复制它们。css 内容。请注意,在字体文件中,有一些应用程序将下载的 URL。如果您的应用程序将在离线环境中运行,您应该下载这些 url 的内容,并将其放在一个子文件夹中:root/assets/fonts,在字体中根据该路径名调整 URL。css 文件)
- 自举。css 标准文件,我将在下面描述(我基本上是从 Bootstrap 网站下载的官方 CSS 文件)
- 一个“corporate-style.css”包含了我在布局中引入的所有定制
我已经看到许多精彩的破折号例子使用了基本的。css 模板(【https://codepen.io/chriddyp/pen/bWLwgP.css】T2):这不是应用程序的要求,我选择不在我的仪表板上使用它(我已经使用了官方的。而是 css 引导文件)。
4.1 使用 CSS Bootstrap 构建布局框架
CSS Boostrap 提供了很多预定义的。我们可以重用的 css 属性、类和布局功能。CSS Bootstrap 以著名的“网格系统”而闻名,它可以根据所用设备的大小来帮助缩放网站页面。
简而言之,我们可以将我们的网页想象成一个由 12 行和 12 列组成的表格:我们的 html 组件可以放在这个网格中,它将根据显示它的设备的屏幕而具有动态的大小。
我认为这对我获得我心目中的布局帮助很大,如下所示:

作者图片
我已经开始从不同的部分(我的页面的“行”)考虑布局,然后在脑海中描绘仪表板的不同列。
我假设,就像在商业场景中一样,一些颜色已经是企业视觉识别的一部分(在这种情况下,是一种带有一些粉色元素的绿色调色板),我选择了一个很好的字体系列,名为 Dosis。
之后,我一直在创建图片中的方案,用不同的占位符和引导列。我用过的 css 类。
在 CSS 引导网格系统中,不同的。div 元素是嵌套的,每个元素都有自己的类,从一行开始,然后是一列或多列。CSS Bootstrap 有不同的列类,从 col-1 到 col-12,这意味着我们可以拥有我们希望的动态列宽,从最大宽度的 1/12 开始,直到使用全部可用宽度(12/12)的列。在每一列中,可以嵌套另一个. Div 的行列序列。
所有这些类都可以分配给 html。Div([])元素,位于它们的 className 属性中。
该系统有助于保持仪表板的每个部分有序,每个仪表板组件都有一个指定的区域,该区域对所使用的屏幕也是动态的。
例如,下面的结构被用来设计标题、导航条和过滤器的样式。
割台包括:
- 外部 html。Div 组件,它有一个. CSS“row”类,用背景色进行样式化
- 三个 html。Div 组件,在行内;每个都代表一个“col”。css 类(记住这些列宽度的总和必须等于 12):一个 className="2-col" div(一个宽度为 2/12 的列),它将保持为空,只是为了确保标题居中;一个 8 列的 div,包含主页标题,最后是另一个 2 列的 div,包含公司徽标图像
作者图片
导航条,包括:
- 在行的两侧有两个空的列 3 格
- 三个中央 col-2 div,每个都包含一个 dcc。链接破折号组件,可用于从一个页面切换到另一个页面。dcc。当前页面的链接页面采用不同的样式,突出显示用户所在的页面
作者图片
过滤器部分由以下部件组成:
在外部,我们有一个行和列 div:
- 外部 html。具有“行粘顶”类的 Div。这是一个 Bootstrap 类,和 row 一样,但是它会停留在页面的顶部,即使用户向下滚动。
- 在行内,有一个 12 列的 Div,带有一些样式属性
在 12 列 div 列中,我们有另一个“行”Div,包含以下一组列:
- 内部行两侧的两个空 col-2 div
- 两个 col-4 div,在内部,每个都包含滤波器组件:一个 dcc。DatePickerRange 和两个 dcc。下拉组件
作者图片
4.2 样式化 Dash 组件访问它们的 CSS 类
一旦定义了布局,从用户界面的角度来看,下一个挑战是正确地设计每个 Dash 组件的样式,比如日期范围(dcc。DatePickerRange)、下拉筛选器(dcc。下拉)等。
所有这些组件都有一个“样式”属性,在这里我们可以定义想要样式化的 css 属性,比如字体大小、颜色、空白等等。我们想要实现的大多数布局增强,都可以通过在 Dash 组件的“样式”中定义正确的 css 属性来实现。然而,我在对这些组件的一些特性进行样式化时面临着不同的挑战,这似乎无法从它们的“样式”属性中获得。我在网上看过许多不同用户的类似挑战,想知道如何设计这些组件的某些功能或细节。
我认为这里的主要挑战是识别 Dash 使用的 CSS 属性。事实上,有一种方法可以指向并单击,或者“检查”页面上的每个元素,并揭示定义它的 CSS 属性。
事实上,我们可以在浏览器中运行应用程序,右键单击页面并选择“Inspect”:这将在页面右侧弹出一个窗口,我们可以在其中浏览页面的 html 和 css 代码。在页面顶部,我们可以点击这个工具

作者图片
我们最终可以将鼠标悬停在想要设置样式的元素上,并获取其所有 CSS 类和属性,以了解要更改/重定义什么。
4.2.1 示例:设置 DatePickerRange 元素的样式
默认情况下,DatePickerRange 如下所示:

作者图片
我们可以从“样式”属性中改变组件布局,定义字体大小,添加一些颜色的边框,等等。但是如何修改分隔开始日期和结束日期箭头呢?如何更改突出显示所选日期或助手图标周围的绿色?
这些元素似乎无法从“样式”属性中获得,我们必须使用不同的方法来更改它们的布局属性。在浏览器中,如果我们检查并选择箭头,我们会看到类似这样的内容:

作者图片
该组件使用了一些 CSS 类,我们可以通过在自定义 CSS 文件中添加一些代码来修改这些类,从而将箭头强制调整为新的大小:
作者图片
同样,我们可以通过检查日历选择来揭示如何更改日历样式:

作者图片
通过分析这一因素,似乎”。CalendarDay__selected”是所选日期极值的 CSS 类,而“CalendarDay__selected_span "是用于两个极端之间的所有日子的 CSS 类。可以使用这些类来改变日历的背景颜色(并在鼠标悬停在不同日期时定义一些布局修改)。我已经将下面的代码添加到自定义 CSS 文件中:
作者图片
("!“important”覆盖同一 CSS 元素或类的任何其他布局定义)。
4.2.2 示例:样式 a dash_table。数据表元素
我发现另一个难以设计的元素是我在仪表板顶部的摘要部分使用的数据表。
默认情况下,数据表有一个功能,可以选择一个单元格,使它以粉红色/红色背景出现。此外,通过使用默认的 CSS 引导文件,默认设置会将我们悬停的所有表格行的背景颜色更改为白色。

作者图片
我想真正改变这两个与我的整体布局相冲突的默认属性。
首先,可选单元格实际上不是一个 CSS 属性,而是一个可以被禁用的组件属性:在创建 DataTable 时添加“cell_selectable = False”会删除此功能。
为了改变行悬停的颜色,用之前解释过的方法我们可以看到,DataTable 行实际上是 html 元素,与特定的 CSS 类没有关联。

作者图片
为了自定义当鼠标悬停在行上时的背景颜色,我在自定义 CSS 文件中添加了以下内容:
作者图片
5.回调和组件
一旦定义了仪表板布局,并且图表和过滤器组件已经放置在页面上,让我们转到回调。
我将介绍一些回调的例子,重点是我用过的最麻烦的例子。
5.1 多下拉过滤器:如何拥有“全选”选项
仪表板通常包括一个或多个下拉过滤器,允许用户同时选择一个或多个值。
在非常简单的情况下,下拉组件“背后”不应该有任何回调:用户选择一个或多个下拉选项;所选的值通常是其他回调函数的“输入”,这些回调函数调整图表上显示的内容。
然而,在更复杂的情况下,我们可能希望有一个多下拉选择,其中第二个下拉的选项取决于第一个下拉的选择。在我创建的例子中,我有一个国家下拉列表和一个城市下拉列表:城市下拉列表选项,当然取决于已经选择的国家。
更复杂的是,我注意到 Dash 中没有“全选”的现成功能。特别是在下拉选项是长列表的情况下,强烈建议添加一个“全选”的方法,否则我们每次想要分析所有值时都需要逐个输入所有选项。此外,我还想以一种“无选择”(即将下拉列表留空)意味着考虑所有选项。
为了实现这里描述的所有特性,我遵循了下面列出的步骤。
创建选项列表
首先,我为每个下拉组件创建了一个选项列表。我随机创建的数据在一列中包含“国家”信息,在另一列中包含“城市”信息。我简单地创建了两个唯一的列表,一个用于所有可能的城市,另一个用于所有可能的国家,我添加了一个“(全选)”条目,我希望它位于选项列表的顶部。
接下来,我在页面布局中包含了 Dropdown 组件,只需指定“multi”属性:
作者图片
5.1.2 动态管理选项列表
然后,我定义了一个回调,它将第一个下拉列表中的值(选择)列表作为输入,将第二个下拉列表中的选项列表作为输出返回。
鉴于选项列表取决于值,我生成了一个字典,其中每个键都是第一个下拉列表的可能值,每个值都是第二个下拉列表的所有可能选项的列表。结果如下所示:
{巴西:[福塔莱萨,里约热内卢,圣保罗],
【米兰、威尼斯】,… }
为了完成回拨,一些关键的考虑事项是:
- 第一个下拉列表中的“值”将是一个 python 列表
- 该列表可能包含也可能不包含“全部”选项
- 将值列表留空意味着我们将把['']作为回调的输入
作为第一步,我创建了一个变量(isselect_all),用于确定用户是否将第一个下拉列表留空,或者用户是否选择了“全选”,或者这两种可能性都没有。
在前两种情况下,回调只是返回所有可能城市的排序列表。否则,用户将分别选择一个或多个国家,因此我将使用之前创建的字典(我将其命名为 repo_groups_l1_l2)来计算所有可能城市的排序列表。
作者图片
5.2 通过热图揭示季节性模式
在所有可能的图表中,当我们想要绘制三维图并显示数据的季节性或模式时,热图是理想的。例如,我包含了一个热图来显示全年(在我的例子中是周数)和一周中的某一天的销售趋势,以查看这两个维度上是否有任何季节性。
x 轴表示工作日,y 轴表示日历周数;每个单元格将根据销售量进行着色。热图还需要响应过滤器(基于日期和城市和国家下拉)。
5.2.1 热图:布局
首先,让我们在 dash 布局中包含一个热图占位符。在下面的代码中,headtmap 将位于 id 为“sales-weekly-heatmap”的最后一列:
作者图片
5.2.2 热图:回拨概述
然后,让我们转到回调,它将有:
- 输入:不同的过滤器——在我的例子中,这些是日期选择器中的开始和结束日期,以及“国家”和“城市”下拉选择
- 输出:上面的 dcc。图形“数字”元素
- 第一部分:数据准备。回调将使用 datasource(由单个 dataframe 组成),并按周 nr 过滤和聚集数据。和工作日
- 第二部分:图形准备(使用 Plotly: go。热图)。该图表将使用预定义的色标,我通过一个函数自定义创建
热图:数据准备
在数据准备部分,我必须包含一些语句来处理两个下拉选择的“全选”。如果用户已经从下拉列表中选择了该选项,则数据框架不需要按照国家/城市进行过滤;否则,仅考虑用户从初始完整数据帧中选择的值:
作者图片
然后,我按开始日期和结束日期过滤数据框架,最后按周数和工作日汇总:
作者图片
热图:图形配置
为了在仪表板上绘制一些漂亮且一致的图表,我创建了一个 go。回调文件顶部的 Layout()变量(名为 corporate_layout)。此布局变量包括许多属性,这些属性在所有仪表板图表中几乎都是相同的(图表透明背景、字体系列、标题字体大小、网格线、零线、总高度、图例、边距等等)。
在每个图表回调中,一个新的 fig = go。图(data=data,layout=corporate_layout)已定义。这允许更新 fig 布局(通过这个命令:fig.update_layout())以适应 corporate_layout 并包括图表标题和轴标题。
使用这种方法,图表的主要布局只定义一次:这有助于保持代码的整洁,同时也很灵活;也就是说,为了改变所有图表的高度,我们只需要调整整个代码中的一个变量。
关于 go 的“数据”部分。我用了一个 go。Heatmap(),包括一个色标,我将在下面描述它。
作者图片
5.2.5 热图:添加自定义色阶
Plotly 热图包括一些标准色阶,我们可以从中选择,或者我们可以指定一个自定义创建的色阶。
Plotly 提供了一些指令(此处可用)来创建自定义色标。我使用的色阶是这样的:根据每个数据点的百分比,热图使用的 11 种颜色的列表。
作者图片
为了以某种渐变顺序生成颜色,我创建了一个函数,它将我们需要生成的颜色数量和两种颜色的 RGB 值作为输入:一种是“起点”,另一种是“目标点”。对于每种颜色,该函数以相同的量递增 RGB 值,直至达到目标值。这是一个非常简单的方法,但是这个函数可以满足目的:
作者图片
我们最终可以将色阶添加到热图中,以揭示一些季节性:正如我们所见,销售额似乎在第 10 周和第 20 周之间下降;然后他们开始增加,在第 25 周达到同样的水平。在一周的几天里,我们没有明显的季节性。

作者图片
5.3 悬停在数据点上时提供附加信息
在 Dash 中,可以定义 hovertemplates 来指定当用户将鼠标悬停在数据点上时,什么数据以什么格式显示。
除了图表已经使用的数据(例如,x 和 y 值)之外,在 hovertemplate 中包含附加信息可能很有用。官方文件提供了有用的选择:我将展示我发现最有效的一个。
在下面的图表中,我创建了一个堆积条形图,其中每个国家由每个竖条表示,将销售额显示为每个城市个人销售额的总和。悬停时,我还想显示关于总目标而非销售额的信息:

作者图片
城市的“目标”是数据源中存在的信息,但它并没有显示在图表中:悬停模板从哪里获取这些信息?
我采用的方法是在图表使用的 dataframe 中创建一个新列,包含我想在 hovertemplate 中显示的所有信息:
作者图片
Plotly hovertemplate 需要一些 html 格式:“T2””例如,意味着内容将是斜体;
一旦数据中有了 hovertext,我们就可以在图表中使用它,只需将 dataframe 列分配给图表 hovertemplate。
6.如何部署和共享仪表板
通过 Dash 创建的仪表板可以部署为 Flask 应用程序。Heroku 无疑是让应用程序在线可用的最有效的方法之一(而且是免费的)。
我用来部署这个应用程序的指南通过这个视频得到了很好的解释,包括一个大约。让这款应用上线的 15 个步骤。
7.结论
Plotly Dash 绝对是一个有趣且非常强大的 Python 库:我一直在寻找一种快速的方法来自动进行可重复的分析,并且非常好地呈现出来,这绝对达到了目的!
凭借 Python 知识、一些 html 和 css 经验,我能够在几周的空闲时间里实现这个仪表板:我必须说,将 CSS Bootstrap 体现到布局中产生了变化,并且肯定允许构建一个底层“网格”,允许以我想要的方式非常容易地控制仪表板的每个部分。
用 Amazon Kendra 和 AWS Fargate 构建一个问答聊天机器人
构建快速问答聊天机器人的分步指南

在 pixabay 上由 manfredsteger 拍摄的照片
亚马逊宣布亚马逊 Kendra 几周前,Kendra 是一个高度准确且易于使用的企业搜索服务,由机器学习提供支持。
在这篇文章中,我将使用 React 和 Amplify 、web socketAPI inAWS API Gateway、 AWS Fargate 和 Amazon Kendra 构建一个问答聊天机器人解决方案。
解决方案提供了问答的对话界面。这个聊天机器人允许用户提出他们的问题,并迅速得到相关的答案。
我们将在这篇文章中讨论的内容:
- 创建一个亚马逊 Kendra 索引,从半结构化文档中提取问题和答案到 Kendra FAQ。
- 在 API Gateway 中部署一个 WebSocket API 来处理问题和回答消息。
- 创建一个 React 应用程序,并使用 AWS Amplify 通过 WebSocket 与这个聊天机器人进行连接和交互。
- 在 AWS Fargate 中创建一个服务,让我们的 bot 调用 Kendra 的 API 来提供答案并将其发送回用户。
下图显示了上述步骤的架构:

为什么 AWS Fargate 如此重要?
构建聊天机器人的一个更简单的方法是使用一个 lambda 函数来查询 Amazon Kendra,而不使用 Fargate。然而,通过 AWS Fargate 或 EC2,我们可以用定制的人工智能模型来扩展聊天机器人,使我们的机器人更加人性化,例如,我们可以基于拥抱脸 最先进的 对话式人工智能模型来构建聊天机器人,并仅查询 Kendra 的特定数据。
如果你的程序是一个长时间的计算任务,需要更多的内存和更高的性能, Fargate 可能是更好的选择。
先决条件
- 设置 AWS 帐户
- 安装最新的 aws-cli
- 安装放大器 cli
- 对 React 的基本了解
- 对 Docker 的基本了解
- 对云形成的基本了解
- 将无服务器框架安装或更新至最新版本
- jq 安装(可选)
现在,让我们开始吧!
创建亚马逊肯德拉指数
让我们创建一个肯德拉指数。亚马逊 Kendra 是一个高度准确且易于使用的企业搜索服务,由机器学习提供支持。Kendra 支持非结构化和半结构化文档,如存储在 S3 的 FAQ,我们将在我们的案例中使用 FAQ。
首先,让我们下载一个 QnA 数据集并上传到 S3。我们可以为聊天机器人使用
微软研究 WikiQA 语料库 。
下载数据集后,让我们转换为 Kendra 支持的 csv 格式,如下所示:

使用以下脚本转换数据集,并将转换后的 csv 文件上传到现有的 S3 存储桶my-kendra-index:
现在,我们准备创建一个肯德拉指数。要创建 Kendra 索引,请完成以下步骤:
- 在 Amazon Kendra 控制台上,选择启动 Amazon Kendra。
- 创建索引并输入索引名,如
my-aq-index。 - 对于 IAM 角色,选择
Create a new role来创建一个允许 Amazon Kendra 访问 CloudWatch 日志的角色。 - 创建索引。
创建 Kendra 索引后,我们可以添加常见问题文档:
- 从亚马逊 Kendra 控制台添加常见问题。
- 对于 S3,浏览 S3 找到您的桶,并选择常见问题 csv 文件。这里我们用
s3://my-kendra-index/faq/faq.csv。 - 对于 IAM 角色,选择
Create a new role以允许 Amazon Kendra 访问 S3 存储桶中的 FAQ 内容对象。 - 添加常见问题。

现在我们有了一个有效的 Kendra 指数,让我们进入下一步。
在 API 网关中部署 WebSocket API 来处理 QnA 消息
在本节中,我们将在 AWS API Gateway 中构建一个 1) WebSockets API, 2) 创建 lambda 函数来管理 WebSockets 路由( \(connect,\)disconnect,sendMessage )和 3) 创建 DynamoDb 来存储 WebSockets 连接 id 和用户名。
我们将使用无服务器框架来构建和部署所有需要的资源。让我们创建一个新的无服务器项目,并将以下配置添加到serverless.yml:
请注意,serverless.yml 中的 Cognito App 客户端 Id ( /chatbot/dev/app_client_id)和 Cognito 用户池 Id ( /chatbot/dev/user_pool_id)尚未创建,我们在此仅引用 Cognito 详细信息为SSM Parameters,在下一步中,我们将使用Amplify Cli创建 Cognito 用户池,然后我们可以从System Storage Manager控制台修改相关的 SSM 参数。
一旦serviceless.yml 被修改,更新handler.js 为 WebSockets 路由创建 lambda 函数:$connect with custom authorizer, $disconnect,sendMessage:
运行以下命令来部署 WebSocket API:
$sls deploy --stage dev --region YOUR_REGION
使用 AWS Amplify 构建 React 应用程序
在本节中,我们将使用 React 和 AWS Amplify 构建一个具有身份验证功能的 web 应用程序。
完整的项目在我的 Github repo 中,你可以在项目目录中找到以下文件夹:
amplify/.config/和amplify/backend/。project-config.json在.config/文件夹中。backend-config.json在backend/文件夹中。backend/文件夹中的云信息文件。
让我们下载源代码,并通过运行以下命令重新初始化现有的 Amplify 项目:
$amplify init
然后推送更改:
$amplify push
并部署:
$amplify publish
我们将在项目部署后获得 web 应用程序 URL:

现在,登录 AWS Cognito 服务控制台,您可以看到 AWS Cognito 用户池已经创建。复制用户池 Id 和应用程序客户端 Id,并将它们用作我们在上一步中已经创建的 SSM 参数。


在 AWS Fargate 中创建聊天机器人服务
在本节中,我们将创建一个 bot 任务,在 AWS Fargate 中运行我们的 chatbot 服务。首先,一个聊天机器人任务连接到一个 websocket API,然后,当用户提问时,机器人可以查询 Kendra 索引,Kendra 将显示相关答案,并将其发送回提问的用户。
要部署 Fargate 服务,请执行以下步骤:
- 点击 下载聊天机器人脚本和 Dockerfile 。
- 构建 Docker,标记一个 Amazon ECR 存储库,并将映像推送到 ECR。更多详情请参考 AWS 官方教程。
- 点击 下载 CloudFormation 模板和 bash 脚本 。
- 如果使用 Fargate 发射类型,则需要
awsvpc network模式。我们需要部署VPC和Security Groups:
$bash create-infra.sh -d dev
5.创建任务定义。
$bash create-task.sh -d dev
6.在 AWS Fargate 中部署聊天机器人服务。
$bash deploy-service.sh -d dev
主要逻辑可以在这里找到:
(可选)用 ConvAI 模型扩展聊天机器人
要使用 ConvAI 模型扩展聊天机器人,您可以尝试下面的示例脚本,注意,您需要投入更多精力来训练模型,并将其放入 docker 或亚马逊 EFS 。
一旦服务被部署,我们应该能够问机器人问题。让我们访问 React 应用程序并进行现场测试吧!

如上所述,仅使用关键字就足以让系统给出正确的答案。

如果你想了解更多关于亚马逊 Kendra 的信息,这里 有一个关于如何使用 Lex 和 Kendra 构建聊天机器人的官方教程。
希望你觉得这篇文章有用,这篇文章的源代码可以在我的 GitHub repo 中找到。
使用潜在狄利克雷分配创建基于时间序列数据的推荐系统
使用经典的 NLP 主题建模技术,根据用户的习惯和偏好对他们进行聚类

卢西恩·阿利克夏在 Unsplash 上的照片
介绍
许多人认为,用户细分和推荐系统的主要目标是预测或更好地理解客户想要或可能购买的东西。然而,有时重要的问题不是顾客可能会买什么,而是什么时候他们可能会买。
考虑下面的例子:(1)一个在线商店想给它最忠实的顾客发送一个符合他们喜好的商品的优惠券。然而,他们也知道顾客通常在一天中的不同时间购物,例如,一些人喜欢在清晨购物,而另一些人喜欢在深夜购物。因此,他们想要确切地知道每个客户(或客户群)何时更有可能购物并在适当的时间发送优惠券。(2)网络代理服务的提供商需要有效地将网络带宽分配给他们的用户。理想情况下,他们会根据用户的活动时间对他们进行分组,并相应地为他们分配带宽。
这些“商业问题”已经假定用户或顾客想要某种产品。他们提出的问题是何时他们最有可能购买或使用它。在这篇文章中,我想分享一个非常简单的方法,它可以添加另一个工具来帮助你回答这样的问题。
我将假设您有一个简单的时间序列数据集,其形式为:
Time ('2020-01-05 10:30')
Entity (user, product, game)
Count (views, orders, downloads)
我将展示 LDA 如何使我们能够(1)根据用户更有可能“活跃”的时间,以一种颇有见地的方式将用户划分成组或簇,以及(2)让我们根据数据预测每个用户与每个组的关联程度。(同样的分析也可以应用于产品,并根据它们更有可能被购买的时间将它们分组,等等)。
在接下来的部分中,我将非常简要地介绍 LDA 及其运行方式,然后深入代码。
潜在狄利克雷分配(LDA)聚类——一个(非常)简短的介绍
LDA 最常用于 NLP 环境中的主题建模,这确实是一个很好的用例来理解它的价值。主题建模算法通常从一个“语料库”或一组由“单词”组成的“文档”开始,并尝试使用观察到的单词混合以及它们一起出现的频率,以便找到文档中的潜在模式或主题。
例如,假设我有 3 个文档:(1)“我的狗吃了我的午餐”;(2)“我就是爱吃水果”;(3)“我对狗过敏”。一个主题建模算法应该能够在这个“语料库”中识别至少两个潜在的主题:一个涉及狗的主题和一个涉及食物或者吃的主题。一些主题建模算法(如 LDA)也能够将一个文档与多个主题相关联,并告诉我们哪个主题在文档中更占主导地位。例如,这些算法将能够告诉我们,句子 1(“我的狗吃了我的午餐”)是既关于狗又关于食物或吃,并且它更多地是关于狗而不是食物。
那么 LDA 是如何做到这一点的呢?
LDA 至少做出两个重要的工作假设:
(1) 每个题目都是一个单词的概率分布。简单来说,每个主题都与处理该主题的文档中以一定概率出现的某些单词相关联。LDA 模型的主要输出之一是术语-主题矩阵,它显示了每个单词在某个主题中出现的概率。这个矩阵允许我们在每个主题中找到语义主题。例如,如果下面矩阵中的单词 0 和单词 1 与动物有关,那么我们可以说主题 3(或其主题)是动物,因为与动物有关的单词很可能出现在其中。

术语-主题矩阵(或特征-聚类矩阵)
(2) 每个文档都有一个“主题食谱”或主题的概率分布。这意味着,例如,在模型中运行句子 1(“我的狗吃了我的午餐”)将告诉我们,基于它包含的单词,该文档 80%关于食物和饮食,20%关于狗。
话题菜谱 sentence | topic-1 | topic-2 | topic-3 | s1 ____| 80% _____| 20% ____| 0% ____ | s2 ____| 50% _____| 30% ____| 20% ____ | s3 ____| 10% _____| 20% ____| 70% ____ |
当我们在某个语料库或某组文档上拟合 LDA 时,它本质上学习每个主题的哪个单词概率分布能够最好地解释(或生成)我们语料库中每个文档中的单词分布。更准确地说,在给定主题配方的情况下,经过训练的 LDA 模型可以再现它被训练的语料库(或者至少在语义上与之相似的东西)。更重要的是,经过训练或拟合的 LDA 模型可以预测模型在训练时看不到的文档的“主题食谱”。

照片由 Ugur Akdemir 在 Unsplash 拍摄
时间序列数据呢?
经过训练的 LDA 模型允许我们估计任何矢量化文档的“主题配方”。在 NLP 的上下文中,“文档”是文本块或单词的弓形向量,文档的主题食谱可以帮助我们找出文档的主导主题,或者哪个主题比其他主题更具主导性。
然而,归根结底,LDA 是一种聚类算法,也就是说,它估计一组具有 N 个特征的向量,并在每个向量中分配给这些特征的值中找到潜在模式。换句话说,如果我们把主题看作集群,把文档的主题配方看作向量的集群配方,告诉我们向量与每个集群的“关联”有多强,那么很明显,我们可以让 LDA 为 NLP 上下文之外的许多业务问题工作。
这似乎与时间序列分析的领域并不完全相关,所以让我直接进入一个例子,我将在这篇文章中使用这个例子来更清楚地说明这一点。
一个例子:用户和电视节目
假设您有一个“客户”数据集,它记录了每个客户在 24 小时内每小时观看的电视节目数量。因此,我们数据集中的每个向量看起来都像这样:
[customer, # of shows watched on 1AM, # of shows watched on 2AM….]
我们的任务是找到一种有效的方法来预测何时是向给定客户提供观看新电视节目的选项的最佳时间。显然,解决这个问题的方法不止一种。我在这里采用的方法是,尝试根据客户看电视的时间将他们分成不同的组,并根据他们最相关的组的偏好或活动来预测向客户提供新电视节目的最佳时间。
艾达能帮我们什么?
如果我们将一天中的每个小时视为一个特征,其值等于客户平均观看的电视节目数量,那么根据该数据估计 LDA 将使我们能够根据客户观看电视节目的时间将他们分成不同的组。

顾客与时间(价值=电视节目数量)
更重要的是,我们将能够生成一个特征聚类矩阵(或小时组矩阵),它将告诉我们哪个小时在哪个聚类中更重要(以及其重要性如何),此外,它还将为我们提供每个客户的聚类方法,它将告诉我们客户与每个组的“关联”有多强。请注意,虽然这项任务也可以使用其他聚类算法(如 KMeans)来完成,但是能够轻松地生成一个特征-聚类矩阵,该矩阵可以量化每个特征与一个聚类的关联的显著性,这是使用 LDA 的一个明显优势(虽然还有更多,但这里的讨论超出了我的范围)。
让我们编码
我们从这个数据集开始:


我们应该做的第一件事是将数据转换成我们想要处理的时间序列格式。
- 我们将时间列固定在数据帧上
df_raw['ts'] = pd.to_datetime(df_raw['ts'])
2.我们使用 pivot_table 方法转置它,以便为每个客户获得一行,每个小时(或时间箱)作为一个特征/列
df_pivot = pd.pivot_table(
df_raw,
index='customerid',
columns='ts',
values='shows',
fill_value=0)

3.最后,我们使用 Panda 的 GroupBy 来获得每个小时的平均值
df_avg = df_pivot.T.groupby(df_pivot.T.index.hour).mean().T
现在,我们有了正确格式的数据

当我们查看整个数据集每小时的平均观看次数时,我们确实看到了某种程度上预期的曲线,其中在黄金时段观看更多的电视节目,而在深夜时段观看较少。然而,正如我们将很快看到的,使用该数据作为何时提供新电视节目的最佳时间的指标忽略了许多偏好偏离平均值的客户。

平均每小时观看的电视节目
简单的魔术发生在这三行代码中
from sklearn.decomposition import LatentDirichletAllocation as LDAlda = LDA(n_components=3, learning_method='batch')lda = lda.fit(df_avg)
我们假设我们的客户的观看偏好可以分为 3 组,并且适合()我们数据上的 LDA 对象。而且,就是这样。我们现在需要做的就是提取数据中潜在的洞察力。
提取洞察力
LDA 产生的第一个也是最重要的洞察是术语-主题矩阵,或时间-聚类矩阵,它将告诉我们每个聚类中哪个观看时间更占优势。这个矩阵通常有助于检查集群是否有意义,或者是否需要进一步调整。
*注意,第一行将生成这个矩阵,但规范化后可读性更好,这就是后面几行的作用。
#Create the hour-cluster / term-topic matrix
df_comp = pd.DataFrame(lda.components_.T, index=df_avg.columns)#Normalize it norm_components = \
lda.components_ / lda.components_.sum(axis=1).reshape(-1, 1)df_comp_norm = pd.DataFrame(norm_components.T, index=df_avg.columns)df_comp_norm * 100

这是一个更精炼的版本:

我们可以清楚地注意到偏好“有意义”的群体。例如,我们可以说 cluster 0 描述了主要在晚上/深夜观看电视节目的客户——他们每天观看电视节目的时间有 40%的可能性(20% + 20%)是在晚上 8 点到午夜之间。我们还看到一个似乎由“每日”观察者(集群 1 )组成的群体,他们在黄金时段上午 8 点到下午 4 点看得最多。
我将很快回到这一点,但是一旦我们的聚类中的小时概率分布有意义,我们就可以使用 transform() 方法,该方法将产生向量-聚类(或客户-聚类)矩阵,该矩阵将显示每个客户与每个聚类的关联程度。

我们之前看到,与第 0 组第 T1 组第 T0 组相关联的主要时间是晚上,而与第 1 g 组第 T2 组相关联的主要时间是中午到下午。因此,我们可以说第一个顾客([0.79,0.14,0.06])主要在晚上看电视节目,而第二个顾客([0.36,0.62。0.01])白天大多看电视剧。如果我们可以选择一个时间段向我们的客户展示新节目,我们可能会选择晚上/夜间,因为尽管第二个客户主要在白天看电视,但他们仍有 36%的机会观看深夜节目。
我们可以通过将每个客户分配到其最主要的聚类,然后绘制每个聚类的平均值来说明这一点。

每个特征的平均值
我们也可以用这个来评估每个组的大小。这将向我们显示,例如,与有些异常的活动时间(集群 2)相关联的组是某种需要进一步探索的异常值(例如,它可能与来自不同时区的用户相关?)

在帖子的开始,我提到了我们需要回答的两个主要问题,或者说我们希望 LDA 帮助我们的两个主要见解:(1)我们希望知道每个组的黄金时段(他们观看最多的时段),以便向每个组的成员提供在他们更有可能观看新电视节目时观看该节目的选项。(2)给定客户的电视观看活动,我们想知道客户与哪个群体的关联有多强。
我们可以用一种相当简单的方法来实现第一个任务,那就是选择每个组或群的平均观看时间,然后找出值超过平均值的小时数。如下例所示,第一组人(守夜人)的黄金时段是下午 4 点到午夜。

至于第二个任务(找到向特定客户呈现电视节目的最佳时间),我们所要做的就是使用我们想要预测的客户的观看时间向量来调用 transform() 方法。

客户 120
我们的模型告诉我们,客户 120 最喜欢在晚上看电视,尽管他们在正常的白天也会花一些时间看电视。换句话说,虽然他们在晚上看更多的电视,但是给他们提供一个新的电视节目让他们在白天看也是值得的。我们可以通过检查他们的实际观看时间来证实这一点。
df_avg.iloc[customerid,:-1].plot.bar()

客户 120
事实上,我们可以看到向客户 120 展示新电视节目的最佳时间是晚上 10 点到凌晨 2 点,尽管他们在白天确实花了相当多的时间看电视。
摘要
总之,我们有相当多的工具可以根据用户的时间序列活动数据对他们进行聚类。我尝试展示了一个相当简单的方法,在分析此类问题时,它肯定可以扩展您的工具集,并轻松产生有价值的见解。
希望这是有帮助的!
你可以在这里找到完整的笔记本
关于 LDA 的一些不错的链接:
[## 潜在狄利克雷分配简介
假设你有下面这组句子:我喜欢吃西兰花和香蕉。我吃了一根香蕉和菠菜…
blog.echen.me](https://blog.echen.me/2011/08/22/introduction-to-latent-dirichlet-allocation/) [## LDA -如何网格搜索最佳主题模型?(带有 python 中的示例)
Python 的 Scikit Learn 提供了一个方便的接口,用于使用潜在的 Dirichlet 等算法进行主题建模。
www.machinelearningplus.com](https://www.machinelearningplus.com/nlp/topic-modeling-python-sklearn-examples/)
使用 Python 创建一个简单的搜索引擎

由 Unsplash 上的absolute vision拍摄
基于余弦相似度和 TF-IDF 加权的术语-文档矩阵的信息检索。
我们所有人每天都在使用搜索引擎,例如谷歌,来搜索一切,甚至是简单的东西。但是你有没有想过,搜索引擎是如何根据我们想要搜索(查询)的内容来检索我们所有的文档的?
在本文中,我将向您展示如何使用 Python 及其支持库从头构建一个简单的搜索引擎。在你看完文章后,我希望你能明白如何根据自己的需要来构建自己的搜索引擎。没有进一步,我们走吧!
边注:我还创建了一个代码的笔记本,所以如果你想跟着我,你可以点击这个链接这里。此外,我将使用的文件是在印度尼西亚。但是不用担心,你可以使用任何语言的文档。
概述
在我们动手之前,让我告诉你如何实现它的步骤,在每一部分,我将解释如何构建它。他们是,
- 准备文件
- 使用 TF-IDF 权重创建术语-文档矩阵
- 使用余弦相似度计算查询和文档之间的相似度
- 检索相似度最高的文章。
该过程
取回文件
我们要做的第一件事是从网上检索文件。在这种情况下,我们可以使用 web 抓取从网站中提取文档。我会从kompas.com搜集体育类的文件,尤其是关于流行的文章。由于文档使用的是 HTML 格式,我们初始化了一个 BeautifulSoup 对象来解析 HTML 文件,这样我们就可以更容易地提取我们想要的每个元素。
根据下图,我展示了带有 inspect 元素的网站截图。在图 1 中,我已经展示了我们想要检索的标签,这是带有类“most__link”的突出显示的标签的 href 属性。在图 2 中,我们将使用类“read__content”从
标签中检索
标签上的文本。 

图 1,图 2
下面是我用来提取文档的代码以及每行的解释,
import requests
from bs4 import BeautifulSoup**# Make a request to the website**
r = requests.get('[https://bola.kompas.com/'](https://bola.kompas.com/'))**# Create an object to parse the HTML format**
soup = BeautifulSoup(r.content, 'html.parser')**# Retrieve all popular news links (Fig. 1)**
link = []
for i in soup.find('div', {'class':'most__wrap'}).find_all('a'):
i['href'] = i['href'] + '?page=all'
link.append(i['href'])**# For each link, we retrieve paragraphs from it, combine each** paragraph as one string, and save it to documents (Fig. 2)
documents = []
for i in link:
**# Make a request to the link**
r = requests.get(i)
**# Initialize BeautifulSoup object to parse the content**
soup = BeautifulSoup(r.content, 'html.parser')
**# Retrieve all paragraphs and combine it as one**
sen = []
for i in soup.find('div', {'class':'read__content'}).find_all('p'):
sen.append(i.text)
**# Add the combined paragraphs to documents**
documents.append(' '.join(sen))
清理文件
就在我们提取文档之后,我们必须清理它,这样我们的检索过程就变得容易多了。对于每个文档,我们必须删除所有不必要的单词、数字和标点符号,将单词小写,并删除加倍的空格。这是它的代码,
import redocuments_clean = []
for d in documents:
**# Remove Unicode**
document_test = re.sub(r'[^\x00-\x7F]+', ' ', d)
**# Remove Mentions**
document_test = re.sub(r'@\w+', '', document_test)
**# Lowercase the document**
document_test = document_test.lower()
**# Remove punctuations**
document_test = re.sub(r'[%s]' % re.escape(string.punctuation), ' ', document_test)
**# Lowercase the numbers**
document_test = re.sub(r'[0-9]', '', document_test)
**# Remove the doubled space**
document_test = re.sub(r'\s{2,}', ' ', document_test)
documents_clean.append(document_test)
使用 TF-IDF 权重创建术语-文档矩阵
每个文档都清理干净后,就该创建一个矩阵了。谢天谢地,scikit-learn 库已经为我们准备了它的代码,所以我们不必从头开始实现它。代码看起来像这样,
from sklearn.feature_extraction.text import TfidfVectorizer**# Instantiate a TfidfVectorizer object** vectorizer = TfidfVectorizer()**# It fits the data and transform it as a vector** X = vectorizer.fit_transform(docs)**# Convert the X as transposed matrix** X = X.T.toarray()**# Create a DataFrame and set the vocabulary as the index** df = pd.DataFrame(X, index=vectorizer.get_feature_names())
结果(矩阵)将成为文档的表示。通过使用这个矩阵,我们可以找到不同文档之间的相似性。矩阵看起来像这样,

术语-文档矩阵
上面的矩阵被称为术语-文档矩阵。它由所有文档中每个标记(术语)代表的行组成,列由文档的标识符组成。单元格内是每个词的频率数,用某个数字加权。
我们将使用列向量,这是一个表示每个文档的向量,用于计算与给定查询的相似性。我们可以称这个向量为嵌入。
为了计算单元格值,代码使用 TF-IDF 方法来完成此操作。TF-IDF(术语频率-逆文档频率)是由 IDF 加权的词的频率。让我解释一下每一个,
术语频率(TF) 是术语(t)在文档(d)上的频率。公式看起来像这样,

除此之外,我们可以使用基数为 10 的对数来计算 TF,因此数字变得更小,计算过程变得更快。此外,请确保在它上面添加一个,因为我们不希望 log 0 存在。

然后,就是逆文档频率(IDF) 。此公式将用于计算该单词在所有文档中的稀有度。它将被用作 TF 的权重。如果一个词比较频繁,那么 IDF 就会小一些。相反,如果这个词用得不频繁,那么 IDF 就会更大。公式看起来像这样,

回想一下 TF-IDF,我们可以看到它是如何影响每个单元格上的值的。它将删除文档中频繁出现但同时并不重要的所有单词,如 and、or、even、actually 等。基于此,我们用它作为矩阵中每个单元格的值。
使用余弦相似度计算相似度。
创建矩阵后,我们可以准备查询,根据文档和查询之间的最高相似度来查找文章。要计算相似度,我们可以使用余弦相似度公式来完成。它看起来像这样,

该公式计算点积除以每个向量上长度的乘积。该值的范围是从[1,0],但一般来说,余弦值的范围是从[-1,1]。因为上面没有负值,所以我们可以忽略负值,因为它从来没有发生过。
现在,我们将实现代码来基于查询查找文档的相似性。我们要做的第一件事是将查询转换成矩阵上的向量。然后,我们计算它们之间的相似度。最后,我们检索相似度值大于 0 的所有文档。代码看起来像这样,
def get_similar_articles(q, df):
print("query:", q)
print("Berikut artikel dengan nilai cosine similarity tertinggi: ") **# Convert the query become a vector**
q = [q]
q_vec = vectorizer.transform(q).toarray().reshape(df.shape[0],)
sim = {} **# Calculate the similarity**
for i in range(10):
sim[i] = np.dot(df.loc[:, i].values, q_vec) / np.linalg.norm(df.loc[:, i]) * np.linalg.norm(q_vec)
**# Sort the values**
sim_sorted = sorted(sim.items(), key=lambda x: x[1], reverse=True) **# Print the articles and their similarity values**
for k, v in sim_sorted:
if v != 0.0:
print("Nilai Similaritas:", v)
print(docs[k])
print()**# Add The Query**
q1 = 'barcelona'**# Call the function**
get_similar_articles(q1, df)
假设我们想找到关于巴塞罗那的文章。如果我们基于此运行代码,我们会得到这样的结果,
query: barcelona
Berikut artikel dengan nilai cosine similarity tertinggi:
Nilai Similaritas: 0.4641990113096689
kompas com perombakan skuad yang dilakukan pelatih anyar barcelona ronald koeman memakan korban baru terkini ronald koeman dikabarkan akan mendepak bintang muda barcelona yang baru berusia tahun riqui puig menurut media spanyol rac koeman sudah meminta riqui puig mencari tim baru karena tidak masuk dalam rencananya di barcelona rumor itu semakin kuat karena puig....Nilai Similaritas: 0.4254860197361395
kompas com pertandingan trofeo joan gamper mempertemukan barcelona dengan salah satu tim promosi liga spanyol elche laga barcelona vs elche usai digelar di camp nou pada minggu dini hari wib trofeo joan gamper merupakan laga tahunan yang diadakan oleh barca kali ini sudah memasuki edisi ke blaugrana julukan tuan rumah menang dengan skor gol kemenangan barcelona....
最后的想法
这就是我们如何使用 Python 及其依赖项创建一个简单的搜索引擎。它仍然非常基础,但我希望你能从这里学到一些东西,并能根据你的需要实现你自己的搜索引擎。谢谢你。
参考
[1] Jurafsky,D. & Martin,j . h .(2000),普伦蒂斯霍尔。
用 python 创建一个垃圾短信分类器
使用 scikit 的自然语言处理基础-学习
介绍
我一直对谷歌的 gmail 垃圾邮件检测系统着迷,它似乎可以毫不费力地判断收到的电子邮件是否是垃圾邮件,因此不值得我们的关注。
在这篇文章中,我试图重建这样一个垃圾邮件检测系统,但是是在 sms 消息上。我将使用几种不同的型号,并比较它们的性能。
这些模型如下:
- 多项式朴素贝叶斯模型(计数记号化器)
- 多项式朴素贝叶斯模型(tfidf 记号化器)
- 支持向量分类模型
- ngrams 参数的 Logistic 回归模型
使用训练测试分割,使 4 个模型经历 X 训练向量化、X 训练和 Y 训练上的模型拟合阶段,进行一些预测,并生成各自的混淆矩阵和接收器操作特性曲线下的面积,以进行评估。(AUC-ROC)
得到的表现最好的模型是逻辑回归模型,尽管应该注意的是,所有 4 个模型在检测垃圾邮件方面表现相当好(所有 AUC > 0.9)。

4 个模型之间的 AUC 得分比较

数据
数据是从 UCI 的机器学习库获得的,或者我也已经将使用的数据集上传到我的 github repo 上。该数据集总共有 5571 行和 2 列:spamorham 表示垃圾邮件状态和邮件文本。我发现这篇课文很有关联,这很有趣。
定义:垃圾邮件是指通常所知的垃圾邮件,ham 是指非垃圾邮件。

spam.head(10)
数据预处理
由于数据集相对简单,不需要太多预处理。垃圾邮件用 1 标记,而 ham 用 0 标记。

df.head(10)
探索性数据分析
现在,让我们详细看看数据集。取“目标”列的平均值,我们发现 13.409%的邮件被标记为垃圾邮件。
进一步说,也许消息长度与目标结果有某种关联?将垃圾邮件和 ham 消息分割成它们各自的数据帧,我们进一步添加消息的字符数作为第三列“len”。

分割的数据帧
EDA 代码
此外,取消息长度的平均值,我们可以发现 spam 和 ham 消息的平均长度分别为 139.12 和 71.55 个字符。
数据建模
现在是有趣的时候了。
列车测试分离
我们首先使用 75%训练测试分割的默认 sklearn 分割来创建训练测试分割。
计数矢量器
我们将 CountVectorizer 拟合到 X_train 上,然后使用 transform 方法进一步转换它。
计数矢量器代码
MNNB 模型拟合
我们先试着在 X_train 和 Y_train 上拟合一个经典的多项式朴素贝叶斯分类器模型 (MNNB)。
一个朴素贝叶斯模型假设它使用的每一个特征在给定某个类的情况下都是条件独立的。在实践中,朴素贝叶斯模型表现得令人惊讶地好,甚至在复杂的任务中,很明显强独立性假设是错误的。
MNNB 模型评估
在评估模型的性能时,我们可以生成一些预测,然后查看混淆矩阵和 AUC-ROC 分数来评估测试数据集的性能。
混淆矩阵生成如下:

MNNB 混淆矩阵
结果似乎很有希望,真阳性率(TPR)为 92.6% ,特异性为 99.7% ,假阳性率(FPR)为 0.3% 。这些结果表明,仅基于消息中的文本,该模型在预测消息是否是垃圾邮件方面表现得相当好。
受试者操作者特征(ROC) 曲线是二元分类问题的评价尺度。这是一条概率曲线,描绘了在不同阈值下 TPR 与 FPR 的关系,并且基本上将‘信号’与‘噪声’分开。曲线下的面积(AUC) 是分类器区分类别的能力的量度,并用作 ROC 曲线的总结。

图片来自本文
该模型产生了 0.962 的 AUC 分数,这明显好于该模型对结果进行随机猜测的情况。
虽然多项式朴素贝叶斯分类器似乎工作得很好,但我觉得通过不同的模型,结果可能会进一步改善
用于拟合和评估的 MNNB (count_vect)代码
MNNB(Tfid-矢量器)模型拟合
然后,我尝试使用一个 tfidf 矢量器来代替计数矢量器,看看它是否能改善结果。
使用 tfidf 的目标是按比例缩小在给定语料库中非常频繁出现的标记的影响,因此这些标记在经验上不如在一小部分训练语料库中出现的特征信息丰富。
MNNB(Tfid-矢量器)模型评估
在评估模型的性能时,我们再次查看 AUC-ROC 数和混淆矩阵。它产生了 91.67%的 AUC 分数
结果似乎很有希望,真阳性率(TPR)为 83.3% ,特异性为 100% ,假阳性率(FPR)为 0.0%。

tfid 混淆矩阵
当基于 AUC 分数比较两个模型时,似乎 tfid 矢量器并没有提高模型的准确性,甚至在预测中引入了更多的噪声!然而,tfid 似乎大大提高了模型检测 ham 消息的能力,达到了 100%的准确率。
用于拟合和评估的 MNNB (tfid_vect)代码
作为一个固执的人,我仍然相信通过一些调整可以获得更好的性能。
SVC 模型拟合
我现在尝试使用 Tfidf 矢量器来拟合和转换训练数据 X_train,同时忽略文档频率严格低于 5 的术语。进一步添加一个附加特征,文档的长度(字符数),然后拟合一个正则化 C=10000 的支持向量分类(SVC)模型。
SVC 模型评估
这将导致以下结果:
- AUC 得分为 97.4%
- TPR 为 95.1%
- 特异性为 99.7%
- 0.3%的 FPR

SVC 混淆矩阵
SVM 装配和评估规范
逻辑回归模型(n-grams)拟合
使用逻辑回归,我还包括使用 ngrams,它允许模型在考虑消息是否是垃圾邮件时考虑最大大小为 3 的单词组。
逻辑回归模型(n-grams)评估
这将导致以下结果:
- AUC 得分为 97.7%
- TPR 为 95.6%
- 特异性为 99.7%
- 0.3%的 FPR
模型比较
在对这 4 个模型进行训练和测试之后,是时候对它们进行比较了。我主要基于 AUC 分数比较它们,因为 TPR 和 TNR 比率都有些相似。
逻辑回归具有最高的 AUC 分数,SVC 模型和 MNNB 1 模型略微落后。相对而言,MNNB 2 型号的表现似乎不如其他型号。然而,我仍然认为,所有 4 个模型产生的 AUC 分数都远高于 0.5,表明所有 4 个模型的表现都足以击败仅随机猜测目标的模型。

4 个模型之间的 AUC 得分比较
感谢你的阅读!
请在此找到代码。
如果你有问题或者想讨论在后新冠肺炎时代应用数据科学技术的想法,请随时联系我。
在世界上最大的职业社区 LinkedIn 上查看韩德·c 的个人资料。韩德有两个工作列在他们的…
www.linkedin.com](https://www.linkedin.com/in/dehan-c-948045177/)
这里还有一篇文章给你!
单词云和条形图中的新加坡#GE2020SG。
medium.com](https://medium.com/@thedehan/pre-elections-sentiment-analysis-880bc5ad1db0)
用 Python 创建股票价格模拟器
几何布朗运动过程的简单应用来模拟股票价格

马库斯·温克勒在 Unsplash 上的照片
来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
在本文中,我将尝试简要解释一种模拟股票价格的方法,这是在寻求减少金融投资的暴露和风险的过程中与金融建模过程相关的研究的结果。
在这种情况下,我利用几何布朗运动 (GBM)过程来模拟资产收益的随机路径,特别是股票。
理解模型的原理:
- 根据这个模型,波动率在股票交易的连续交易期内保持不变。
- 预期收益对股票的表现有独立的行为。
- 另外,回报是正态分布,也就是说大规模(指几十万或者几百万)计算,回报趋向于平均值为 0,标准差为 1。
本质上,股票价格在每个交易周期都会有一系列回报,我们正试图以恒定利率复制这种行为,这通常也称为“漂移”,我们在资产价格中添加随机的正或负偏差,也称为“冲击”。
事实证明,所有这些概念都可以很容易地反映在一个 Python 代码中,以利用计算能力的优势,让我们在几毫秒内完成数千次计算。
在这段代码中,我只使用了 Python 的标准库中的模块,这意味着可以通过实现其他库(如 Numpy)来提高计算效率。
- 首先,继续导入数学和随机数生成器库。
- 其次,编写自动计算股票价格的函数,当然是通过 GBM 过程的应用。
- 最后,以达到某个目标为目标,执行一个由数千个模拟组成的循环,在其中模拟股票价格。在我的例子中,130 美元是从最初的 100 美元开始的理想价格,如果资产的随机行为不允许,这肯定是无法达到的。
说实话,尽管这种模型在金融领域有无数的应用,但当用于真实交易场景时,它往往会显示出的缺点,因为它的主要假设是恒定预期收益和恒定波动率,而实际上这并不是现实。
为了评估模型的这些低效率,最好将这些参数建模为随机过程,这意味着它们是独立分布的,与资产的表现无关。
毫无疑问,有很多像这样的编程技能的金融应用,由于技术的使用,这些应用很容易实现。为这个生态系统的发展做出贡献是我们挑战的一部分。
感谢您花时间阅读我的文章!如果您有任何问题或想法要分享,请随时通过我的电子邮件联系我,或者您可以在以下社交网络中找到我以了解更多相关内容:
在 30 小时或更短时间内创建一个监督模型
构建机器学习模型的 8 个步骤

TL;速度三角形定位法(dead reckoning)
- 加载用于进行预测的数据
- 调查数据
- 选择模型的功能
- 将数据拆分到训练和验证集合
- 预处理数据
- 训练模型
- 使用验证集测试模型
- 重复步骤 2 到 7,直到您对模型的准确性感到满意
这个帖子是在以色列最大的高级女性工程师和计算机科学家社区的 #30_hours 计划期间创建的。在 30 小时计划中,参与者投资 30 小时(超过 4 个月)在一个新的领域加深他们的知识,通过与专业导师一起建立一个个人或小组项目。
加载数据
在现实世界的场景中,您可能需要从收集数据开始。我们将跳过这一步,在本文中使用 Kaggle 房价数据集。

房屋数据的部分数据框架
在这个数据集中,我们既有房子的数据——比如房子的状态、位置和出售时间的数据——也有房子的售价。
我们可以使用监督学习训练一个模型,将给定的输入(称为特征,如房屋状况和位置)映射到给定的输出(称为标签,如销售价格)。
首先,让我们使用 pandas 来读取 csv 文件。标签由y表示:
import pandas as pdhouses_df = pd.read_csv(PATH_TO_TRAIN_DATA)
LABEL = 'SalePrice' # let's make this a constant for future usage
y = houses_df[LABEL]
接下来,我们将了解哪些特征可以帮助我们预测房屋的价格。
调查数据
那需要一段时间!
在选择特性之前,我们需要了解我们的数据是什么样的。让我们从数据列开始:
print(houses_df.columns)"""
Output:
Index(['Id', 'MSSubClass', 'MSZoning', 'LotFrontage', 'LotArea', 'Street', …, 'YrSold', 'SaleType', 'SaleCondition', 'SalePrice'],
dtype='object')
"""
我们有 80 列可以帮助我们预测销售价格。让我们仔细看看每一列。我们将使用两种方法来调查我们的数据:
- value counts() 获取唯一值的计数(包括
NA值,因为我们想知道我们的列包含多少个空值) - describe() 根据数据类型生成描述性统计
在下面的示例中,我们可以看到“Street”有两个唯一的值,并且几乎都是“Pave”。我们还可以看到大多数“小巷”值都不见了。由于这些数据列没有变化,我们无法了解不同街道或小巷的价格差异。
for col in houses_df.columns:
print(f'_____Column: {col}_____')
# normalize=True - use relative frequencies of the unique values
# dropna=False - include NA values
print(houses_df[col].value_counts(normalize=True, dropna=False))
print(houses_df[col].describe())"""
Output:
_____Column: Street_____
# value_counts:
Pave **0.99589**
Grvl 0.00411
Name: Street, dtype: float64# describe:
count 1460
unique 2
top Pave
freq 1454
Name: Street, dtype: object_____Column: Alley_____
# value_counts:
**NaN** 0.937671
Grvl 0.034247
Pave 0.028082
Name: Alley, dtype: float64# describe:
count 91
unique 2
top Grvl
freq 50
Name: Alley, dtype: object
"""
为了简化调查数据的过程,您可以使用 Kaggle 上为该数据集提供的可视化来获得每个数据列的更多信息。你也可以在这里看看我的代码示例。

点击数据选项卡,向下滚动并选择 train.csv 查看可视化|来源:Kaggle
选择模型的特征
我们希望只选择有助于预测房屋价格的特征,以便降低计算成本并提高模型的性能—这个过程称为特征选择。
选择,选择..!
对于这个例子,我们将简化这个过程,但是你可以阅读更多关于特征选择和如何识别相关特征的内容。
下面是一个简化的特征选择示例。特征由X表示:
include_features = ['MSSubClass', 'MSZoning', 'LotFrontage', ..., 'MoSold', 'YrSold']
X = houses_df[include_features]
拆分数据
模型的工作是在数据中寻找模式,以便预测标签——模式来自模型训练的数据。为了对模型的准确性进行公正的评估,我们需要根据它没有训练过的数据来验证它。
为此,我们将数据分成(至少)3 个部分:
- 训练集-用于训练模型的数据
- 验证集—在调整模型的超参数(模型的属性)并选择性能良好的模型时用于评估模型的数据—该集仅用于调整模型的超参数,其数据不应用于训练模型!
- 测试集——用于评估最终模型的数据——它在模型训练期间对模型没有影响,因此是无偏的
因为我们使用的是 Kaggle 竞争数据集,所以我们已经在一个不同的文件(test.csv)下提供了一个测试集。我们只需要将训练集分成训练和验证。
我们使用 train_test_split 将数据分成两部分。
稍后,我们将看到验证集如何帮助我们调整模型。
from sklearn.model_selection import train_test_splitX_train, X_valid, y_train, y_valid = train_test_split(X, y, train_size=0.8, test_size=0.2, random_state=1)
random_state 值被设置为某个常数,以避免训练模型时的随机性。
预处理数据
我们使用 Python 中的机器学习库 scikit-learn 来创建模型。Scikit-learn(或 sklearn)期望数据是数字的和有意义的。真实世界的数据可能有缺失值,或者可能包含非数字值(分类值、图像等),因此与 scikit-learn 不兼容。
对对对。
在我们可以训练模型之前,我们需要准备数据,以便我们可以将它馈送给 scikit-learn。这一步叫做——你猜对了——预处理!

我们如何处理丢失的值?
- 最简单的方法是删除缺少数据的要素/条目。这会导致可能对更准确的预测有价值的数据丢失,因此不建议这样做
- ****输入现有数据中的缺失值,例如,输入特征的平均值。分类特征没有“平均值”——我们可以使用“最频繁”策略来填充缺失值(我们使用的是 SimpleImputer ):
from sklearn.impute import SimpleImputer# allowed_strategies = ["mean", "median", "most_frequent", "constant"]
numerical_imputer = SimpleImputer(strategy='mean')
categorical_imputer = SimpleImputer(strategy='most_frequent')
我们如何处理分类数据?
我们希望将分类数据编码成数字数据。我们可以使用不同的编码器。例如,我们可以使用带有标签编码的类别排序。如果类别没有排序,我们可以使用一键编码,它为每个类别创建一个新的特性,并用布尔值填充它。阅读更多关于清洁和预处理数据的信息。

标签编码(左)和一键编码(右)|来源:Kaggle
为分类值创建一个编码器—在本例中,我们将使用 OneHotEncoder,但选择可以而且应该根据您的数据而有所不同:
from sklearn.preprocessing import OneHotEncoderone_hot_encoder = OneHotEncoder(handle_unknown='ignore')
您可以更进一步,预处理数字数据来创建一个更加精确的模型!****
拟合模型
差不多到了适合模型的时候了!
我们看到了如何估算缺失值和编码分类值。让我们在一个管道中定义这些步骤,使我们的代码更干净,更容易调试。
我们为数据中的每个列类型定义了一个管道,在我们的例子中,我们需要处理数字和分类数据:
from sklearn.pipeline import Pipeline
# impute and scale
numerical_transformer = Pipeline(steps=[
('imputer', numerical_imputer),
('scaler', StandardScaler())
])# impute and encode
categorical_transformer = Pipeline(steps=[
('imputer', categorical_imputer),
('onehot', one_hot_encoder)
])
很好,我们现在为每种列类型都提供了一个管道。让我们为数据列捆绑这些预处理步骤:
from sklearn.compose import ColumnTransformer# get columns from X_train
numerical_cols = get_numerical_columns(X_train)
categorical_cols = get_categorical_columns(X_train)preprocessor = ColumnTransformer(
transformers=[
('num', numerical_transformer, numerical_cols),
('cat', categorical_transformer, categorical_cols),
])
注意,在这个例子中,我们通过数字/分类数据捆绑了预处理步骤——实际上,您可能希望使用与数据列最匹配的步骤。在研究数据时,您应该看到哪些预处理步骤最适合不同的列,而不是使用“一刀切”的方法。
现在我们已经为训练集定义了预处理,我们可以用它来训练我们的模型了!
但是等等…
您可能会问自己——我们不应该预处理所有的数据,而不仅仅是训练集吗?
答案肯定是否定的!如果我们基于所有数据进行预处理,我们将深入了解我们正在验证的数据,从而导致假阳性评估!包括来自列车组外部的信息被称为数据泄漏。
现在让我们使用管道来拟合模型!
受监督的模型可以是分类模型,它输出一个离散的结果,如预测一封电子邮件是否是垃圾邮件,也可以是回归模型,它输出一个连续的结果,如预测房价。阅读更多关于常见 ML 型号的信息。
我们将使用随机森林回归模型——决策树的集合。

决策树示例|来源:Kaggle
定义预处理和拟合随机森林回归模型的管道:
from sklearn.ensemble import RandomForestRegressormodel = RandomForestRegressor(n_estimators=ESTIMATORS_VALUE, random_state=1)pipeline = Pipeline(steps=[
('preprocessor', preprocessor),
('model', model)
])
还记得验证集吗?
这是我们最终使用验证集的地方。
n_estimators 是 RandomForestRegressor 模型的数值型超参数。我们可以使用不同的n_estimators值根据验证集创建和评估我们的模型,最终选择最接近验证数据上实际标签的预测值——这样做会导致我们的模型被验证集调整,这就是为什么我们需要一个测试集,一个模型没有见过或已经被调整过的数据集。n_estimators也用于控制示例模型中的欠拟合和过拟合。
现在,我们可以使用之前定义的所有步骤,使用该管道来拟合我们的模型:
pipeline.fit(X_train, y_train)
啊啊啊……我们终于有一个合身的模型了!
啊哈。
测试模型
模型能在没见过的数据上成功预测房价吗?让我们使用损失函数来测试这个模型——这个函数可以帮助我们计算原始标签和预测标签之间差异的“成本”,从而帮助我们估计这个模型有多精确。
我们可以使用的一个常见损失函数是 MAE ( 平均绝对误差),它计算原始标签和预测标签之间的绝对差异——较低的 MAE 分数意味着对验证数据的预测更好。
from sklearn.metrics import mean_absolute_errorpredictions = pipeline.predict(X_valid)
mae_score = mean_absolute_error(y_valid, predictions)
你可以玩不同的超参数值,特征,模型和预处理步骤,看看模型的分数如何变化。
下一步是什么?
现在你已经有了一个满意的模型,你可以将预测保存到一个. csv 文件,上传到 Kaggle,然后继续下一个挑战!****
output = pd.DataFrame({'Id': house_df.Id, label: LABEL})
default_filename = f'submission-{mae_score}'
output.to_csv(f'{filename}.csv', index=False)
你可以在这篇文章的末尾找到完整代码的链接。
你做到了!
总结我们所学的内容
- 基本术语(参见备忘单)
- 如何用熊猫调查数据(见 100 个熊猫小窍门
- 为什么我们需要至少 3 组数据
- 如何用 skicit-learn 对数据进行预处理
- 分类模型与回归模型有何不同**
- 如何使用 skicit-learn 创建管道
- 什么是平均绝对误差以及我们如何使用它来测试模型
如果这篇博文对你有帮助,请随意与你的朋友分享!
完整代码见此处。
创建一个合成图像数据集——“什么”、“为什么”和“如何”
缺少图像来训练你的模型?以下是如何使用图像合成技术通过合成图像将数据集的大小增加数倍。

把你的狗送上月球!图像合成技术的一个例子(来自 Pexels 的海伦娜·洛佩斯和皮克斯拜的原始照片)
众所周知,用于训练模型的数据集的质量和数量将直接影响模型的性能。一个广泛、通用的数据集的可用性可以达成协议,你可以跳到你的机器学习/深度学习管道的下一步。但是,您可能经常会遇到这样的情况:您需要的数据集并不容易获得。或者你所拥有的数据不足以训练一个重型模型。现在你做什么?
有许多资源可以帮助您创建任何所需对象类的新自定义数据集。但是如果我必须用一个词来描述构建数据集的过程,我会称之为“繁琐”、“耗时”和“令人沮丧”——我知道我用了不止一个词,但是你明白我的意思了!
尤其是在画分割蒙版的时候,我就是懒得去注释超过几张图片的东西!不要误解我,我知道数据集创建是一个非常非常非常重要的步骤,但是难道没有解决的办法吗?
数据扩充是增加你的模型看到的数据集的多样性的一个很好的方法,但是同样,它的帮助是有限的。不如我们更进一步?
什么是合成数据集?
创建任何类型的数据(图像、音频、文本等。)“人工地”或“程序地”产生我们所说的合成数据集。这些数据不是自然或正常收集的,也不是手动标记的,所以用它来训练你的模型安全吗?会有好的结果吗?
虽然有许多论文声称精心创建的合成数据可以提供与自然数据不相上下的性能,但我建议将两者健康地结合起来。设计良好的合成数据集可以将数据扩充的概念提升到下一个级别,并为模型提供更多种类的训练数据。越多越好,对吗?
创建合成影像数据集有多种方法,在本教程中,我们来看看最基本的方法之一——影像合成。我们将通过将目标图像作为前景合成在多个背景图像上来生成新的图像。
在本教程中,我将为输出类“dog”创建合成图像。事实上,网上有许多现有的数据集包括狗类(例如,可可),但创建更多这些大自然可爱礼物的图片有什么坏处呢?😛
1.进口
看看下面的导入语句。安装任何你可能还没有的模块。
import os
import numpy as np
import skimage.io as io
import skimage.transform as transform
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
%matplotlib inline
2.对象—前景
有两种方法可以解决这个问题—
(A)创建自己的数据集
首先,让我们拍一张网上可以买到的狗的照片。有几个网站允许你免费使用这些图片,比如 pexels 、 flickr 、unsplash——随你挑。我要用下面这个。

照片由 Matheus Bertelli 从 Pexels 拍摄
下一步,你将不得不投入一点体力,把狗从背景中分离出来。是的,很抱歉——没有免费的午餐。但最终这肯定比创建一个完整的数据集要简单,我保证。
我所知道的完成这项工作的几个工具是 Photoshop (付费)或 GIMP (免费)。或者你甚至可以使用永远可靠的微软油漆!最终输出如下所示。

狗的分段图像
阅读图像。接下来,从这个图像中剪切出前景层,并将剩余的像素设置为零。编码这一步的另一种方法是在分割图像本身时,用你使用的工具(GIMP/Paint/Photoshop)添加一个黑色背景。但尽管如此,下面是如何在 python 中提取前景对象——简单的像素阈值处理。
# Read the image
I = io.imread('./dogSeg.jpg')/255.0# Cut out the foreground layer
foreground = I.copy()
foreground[foreground>=0.9]=0 # Setting surrounding pixels to zeroplt.axis('off')
plt.imshow(foreground)
plt.show()

周围像素设置为零,前景层保持不变
(B)使用现有数据集
如果您不想从头开始,另一种选择是利用现有数据集中的图像。
我将在这里使用 COCO 数据集来演示。既然 COCO 已经有了对象类别“狗”,那么检索图像和它的遮罩就很容易了。COCO 数据集对于“狗”类别具有 4385 个(训练)和 177 个(val)图像。
对于本教程,你可以参考我的 GitHub 库中这个过程的全部代码。在这篇文章中,我将不再赘述这一步的代码。


可可图片(左)及其标注(右)


分割蒙版(左)和剪切出的前景层(右)
如果你对操作 COCO 图像数据集和创建一个数据生成器来训练你的图像分割模型感兴趣,我这里有一个广泛的教程。
3。增强前景
让我们和狗玩一会儿(双关语)。我在代码中使用了随机旋转、随机缩放、随机平移和随机水平翻转,但是你也可以使用其他方法。
代码的输出如下所示。看它和原图有多不一样!

增强前景图像
将所有这些变化应用到前景后,让我们从图像中提取分割蒙版。

增强前景的分段遮罩
4.背景
现在你需要一个新的背景图片。使用我前面提到的免费网站来获得各种各样的背景。你可以选择世界上的任何图像(见本文展示图片中我是如何把我的狗送上月球的),但我建议尽量保持逼真。
我将使用这 4 张图片作为本教程的背景。


**
来自 Pexels 的创意 Vix 、皮克斯拜和内森考利的照片
让我们随机选择一个背景。
*# Random selection of background from the backgrounds folderbackground_fileName = np.random.choice(os.listdir("./backgrounds/"))
background = io.imread('./backgrounds/'+background_fileName)/255.0*
5.最后:合成前景和背景
是时候把你的狗图像添加到背景中了!
该函数给出以下输出。现在,我知道它并不完美,但它相当不错!

最终合成的图像
对于对象定位任务,您也可以从我们开发的新分割遮罩中轻松获得框坐标。

图像上标记的对象框
在所有背景下循环执行这些功能,我们得到了一组漂亮的图像!

一只狗在多种背景下的合成图像
在本教程中,我使用了 1 个前景和 4 个背景。如果你随机使用多种背景和多种前景,你可以创造出很多很多的图像!也许你也可以在一个背景上合并两个或更多的前景。发挥创意——根据您的需求,调整大小、角度、前景和背景,构建一个令人惊叹的合成数据集。这里也有很多设计上的考虑,但是只需一点点努力,你就可以做得更多,创建更精确的数据集。**
最后,你可以在我的 GitHub 资源库 中找到本教程的完整代码。
作为这个主题的下一步,看看这个关于用 Unity 3D 创建合成图像数据集的漂亮的教程。
好了,现在就到这里——谢谢你一直阅读这篇文章。我希望会有好的结果。有什么想法,问题,评论吗?请在下面的回复中告诉我!
如果你对语义分割的图像数据集感兴趣,可以看看我下面的帖子:
使用 PyCoco、Tensorflow Keras Python…探索和操作 COCO 图像数据集进行语义图像分割
towardsdatascience.com](/master-the-coco-dataset-for-semantic-image-segmentation-part-1-of-2-732712631047)
还是想在股票上用 ML 一夜暴富?这篇文章(不)适合你!
股票和机器学习——天作之合。但是事情真的像看起来那么简单吗?
towardsdatascience.com](/how-not-to-predict-stock-prices-with-lstms-a51f564ccbca)
ML 模型真的能读懂股价图吗?
股票和机器学习——天作之合。如果你的 ML 模型可以从字面上阅读价格图表…
towardsdatascience.com](/can-an-ml-model-read-stock-charts-and-predict-prices-fb73c551c7a4)*
创建一个电报机器人来帮助你学习一门新的语言
网络抓取和谷歌文本到语音的 API 来拯救

莱昂纳多·大久保俊郎在 Unsplash 上的照片
介绍
由于新冠肺炎疫情爆发,我在家有很多空闲时间,所以我试着学习一项新技能。上周我决定开始学习韩文(韩文字母)。
为了阅读和说韩语,你首先需要理解韩文,但有时韩文的书写方式与我们的发音不同。
学习如何发音某个韩国语单词的一种方法是通过在谷歌翻译中复制这些单词并听如何发音。

GIF 1:利用谷歌翻译功能(音频)学习韩文发音
但这似乎很累人,因为我们需要不断地从一个应用程序转移到另一个,并做一些复制粘贴。
在本教程中,我们将构建一个电报机器人,它将帮助我们以一种简单的方式实现我们的目标(学习如何发音韩语单词)。
我们将抓取一个韩语网站(在本例中是 BBC 韩国 ) →获取一些单词→使用谷歌文本到语音转换 API 创建关于如何发音的音频文件→保存它。然后,机器人会发送单词和音频文件来帮助我们学习如何阅读韩文和发音。
这是我们将要创建的一个机器人的例子。

GIF 2:机器人的例子
看起来很酷吧?我们开始吧!
PS:如果你正在学习其他语言,你也可以修改脚本来学习如何用你的首选语言发音某些单词。
入门指南
1.安装库
我们将使用 Requests 和 BeautifulSoup 来抓取网站,使用Google Text-to-Speech API来创建关于如何发音韩文的音频,使用 Pandas 来帮助我们处理数据,使用 python-丨t丨e丨l丨e丨g丨r丨a丨m丨s丨-bot 来创建机器人。
pip install requests beautifulsoup4 google-cloud-texttospeech pandas python-丨t丨e丨l丨e丨g丨r丨a丨m丨s丨-bot
2.启用 Google 文本到语音转换 API 并设置凭证
转到谷歌文本到语音转换 API 指南。在开始部分之前的中,遵循指南,直到在步骤 5 中完成环境变量的设置。
在这一步之后,您应该有一个格式为.json的凭证(在本教程中,我们将其命名为creds.json),并且您应该有一个指向您的creds.json路径的环境变量GOOGLE_APPLICATION_CREDENTIALS。
3.在 BotFather 中创建新的机器人
如果你想在 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 中制作一个机器人,你必须在使用它之前先注册你的机器人。当我们注册我们的 bot 时,我们将获得令牌来访问 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 API。
转到机器人父亲,然后通过发送/newbot命令创建一个新机器人。遵循这些步骤,直到您获得您的 bot 的用户名和令牌。您可以通过访问这个 URL: [https://丨t丨e丨l丨e丨g丨r丨a丨m丨s丨.me/YOUR_BOT_USERNAME](https://丨t丨e丨l丨e丨g丨r丨a丨m丨s丨.me/YOUR_BOT_USERNAMEa) 来访问您的 bot,您的令牌应该如下所示。
704418931:AAEtcZ*************
写程序
我们将为本教程创建两个脚本。第一个用于准备数据集(抓取网站、创建音频和保存数据),第二个用于运行机器人。
1.准备数据集
让我们为这个任务导入必要的依赖项。
from google.cloud import texttospeech
from bs4 import BeautifulSoupimport pandas as pd
import requests
import re
我们将从 BBC 韩国抓取特定页面,即头条新闻页面并获取新闻标题。

图 1: BBC 韩国-头条新闻
如果我们看看 Google Chrome inspect 元素,每个标题都被包装在 span 元素和most-popular-list-item _ _ headline类中。这是使用 BeautifulSoup 抓取特定元素的代码。
url = '[https://www.bbc.com/korean/popular/read](https://www.bbc.com/korean/popular/read')'
page = requests.get(url)
soup = BeautifulSoup(page.content, 'html.parser')
titles = soup.findAll('span',
{'class': 'most-popular-list-item__headline'})
现在我们迭代titles,获取新闻标题,拆分成文字,追加到一个列表中。我们使用正则表达式删除标题中的任何标点符号。
result = []for title in titles:
title = re.sub(r'[^\w\s]', '', title.text)
words = title.split()
result += words
将上面的代码包装到一个名为get_hangeul的函数中,这样您的代码看起来就像这样。
请注意,我们使用return set(result)是因为我们希望列表具有惟一的值,我们可以使用Python Set来实现这一点。
在我们获得 Hangeul 之后,我们将使用 Google 文本到语音 API 为每个单词创建音频文件,并将其保存在一个名为audio的文件夹中。
我在创建音频数据部分使用了谷歌文本到语音快速入门指南中的代码。我们稍微修改一下,把代码包装成带text(韩语单词)和language(默认为 ko-KR,是韩语)的create_audio函数,将音频保存在audio文件夹中。
现在创建调用get_hangeul的主函数,遍历其结果并保存音频文件,同时保存名为dictionary.csv的.csv格式的韩语单词列表。
words = get_hangeul()for word in words:
create_audio(word)dictionary = pd.DataFrame(words, columns=['word'])
dictionary.to_csv('dictionary.csv', index=False)
使用这些主函数,包装上面的所有代码,并将其保存为dataset.py。您的文件应该如下所示。
酷!从终端运行脚本(不要忘记首先在与dataset.py相同的路径中创建文件夹audio)。
python dataset.py
运行脚本后,您将会看到,我们在audio文件夹和dictionary.csv中有.mp3文件。
太好了!数据集准备好了,让我们创建机器人。
2.创建电报机器人
我们的机器人如何工作非常简单。每次用户发送/word命令时,我们将从dictionary.csv中随机抽取一个字,并与相应的.mp3文件一起发送。
首先,导入库并设置日志功能(这是为了在遇到错误时调试 bot)。
from 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨.ext import Updater, CommandHandlerimport pandas as pd
import logging logging.basicConfig(level=logging.DEBUG,
format='%(levelname)s - %(message)s')
logger = logging.getLogger()
logger.setLevel(logging.ERROR)
让我们为机器人的主要任务创建一个函数。在这个函数中,机器人将读取dictionary.csv文件,随机选取一个单词,然后将这个单词和音频文件发送回用户,并将其包装在一个名为send_word的函数中。
现在创建一个主函数来运行机器人。
当我们写CommandHandler('word', send_word))时,这意味着每次用户发送命令/word给机器人,它将运行send_word功能。
将所有这些代码合并到一个名为main.py的文件中。您的文件应该如下所示。
现在您可以在终端中运行main.py文件。
python main.py
如果一切运行正常,您应该看到您的机器人在您向机器人发送了/word 命令后发回了单词及其音频。
恭喜你!不难吧?现在你有了一个帮助你学习新语言的电报机器人,酷!
进一步发展
我知道这远非完美,所以如果你想进一步开发这个机器人,让它变得更酷,这里有一些建议。
- 使用 cron job 或 python-丨t丨e丨l丨e丨g丨r丨a丨m丨s丨-bot 作业队列自动抓取网站,这样字典就会扩展。
- 添加功能,机器人将发送这个词,我们必须发送我们的声音(使用语音笔记)发音,然后使用谷歌语音到文本 API 我们将验证我们是否发音正确或错误。
- 更多…
你可以访问我的 GitHub 个人资料获取代码或者在这里查看工作机器人。
如果您有任何问题,请随时联系我,并在我的 Linkedin 个人资料中留言。
如果你对数据科学或机器学习感兴趣,你可能想看看我关于构建情感分析器和使用 Python 自动化任务的帖子。
再次感谢你,祝你好运!😃
从代码创建一个 YouTube 视频
用 C++演示创建分形缩放

由沃尔夫冈·拜尔用超分形 3 程序创建。( CC BY-SA 3.0
如果你是一名计算机程序员,曾经想过创建一个包含计算机生成动画的视频,那么这篇文章就是为你准备的。在这里,我假设您已经有代码,或者可以编写代码,将某种图像创建为二维像素数组。它是什么样的图像并不重要,只要它适合内存中的数组。
如果你能做到这一点,这篇文章将带你走完剩下的路。您将了解如何创建 MP4 视频文件的详细步骤。当我们完成后,你将有一个适合上传到 YouTube 的视频文件,就像这样:
Mandelbrot 设置缩放视频由作者生成。
计划概述
以下是创建计算机生成视频的步骤概要。
- 将生成图像的 C++代码写入内存数组。我将使用一个简单的 Mandelbrot 集合图像生成器,但同样,这可以是你想要的任何东西。
- 使用开源库 LodePNG 将该图像保存到磁盘上的 PNG 文件中。
- 这段代码重复前两步数百次,一次生成一个视频帧。每个 PNG 输出文件为您的电影保存一个静态帧图像。
- 在 Windows 或 Linux 上,使用 ffmpeg 将一系列 PNG 图像转换为 MP4 视频格式文件。
Mandelbrot 集合图像
Mandelbrot 集合是最著名的分形物体之一。上面的视频将曼德布洛特集合的放大倍数从 1 倍逐渐增加到 1 亿倍。该视频以每秒 30 帧的速率持续 30 秒,总共快速连续播放了 900 幅图像。
值得注意的是,如此多的视觉复杂性从迭代微小的公式中显现出来
源文件 mandelzoom.cpp 中的Mandelbrot函数迭代该公式,直到复值 z 超出原点半径为 2 的圆,或者 n (迭代次数)达到最大限制。 n 的结果值决定了屏幕上给定像素的颜色。
看一下函数Palette,看看迭代计数是如何转换成红色、绿色和蓝色值的。
在内存中生成图像
函数GenerateZoomFrames产生一系列 PNG 输出文件。每个 PNG 文件都包含一个以不同放大率渲染的 Mandelbrot Set 图像。帧图像的分辨率为 1280 像素宽 720 像素高,这是标准的 HD 720p 视频尺寸。
将图像保存到 PNG 文件
对于您自己的视频生成器应用程序,类VideoFrame可能会有所帮助。它表示视频的单个帧,并知道如何将该帧保存为 PNG 文件。函数GenerateZoomFrames使用VideoFrame生成分形缩放电影的每一帧。
您的应用程序必须为每一帧的每一个像素调用成员函数VideoFrame::SetPixel。您传入一个定义像素的红色、绿色和蓝色分量的PixelColor结构。这些值都是 0 范围内的整数..255.
PixelColor还包含范围为 0 的 alpha 值..255 表示像素的透明度。对于视频应用程序,您应该始终将此设置为 255,这意味着像素完全不透明。为了通用性,我包括了 alpha 值,以防您希望生成具有透明区域的 PNG 文件。
使用 ffmpeg 创建电影
我包含了一个 bash 脚本run,它自动化了从源代码构建 mandelzoom 程序、运行它,以及将生成的 900 个 PNG 文件转换为名为zoom.mp4的电影文件的整个过程。这最后一步是通过运行 ffmpeg 程序来完成的。下面是run脚本。它包括一些有用的注释,解释 ffmpeg 的命令行参数。
这就是全部了!您可以使用本文末尾“参考资料”一节中的链接下载整个源代码库mandelzoom。
另一个例子
我提到过,这种技术可以用于创建你能想象的任何类型的视频,只要你能编写代码来创建每一帧。只是为了好玩,我以我创建的另一个 YouTube 视频样本作为结束。它是基于一个简单的光线追踪我为我的书 光线追踪 的基础创建的。创建这个视频的代码与上面的 Mandelbrot zoomer 工作方式相同:它生成一系列 PNG 文件,然后 ffmpeg 将其转换为 MP4 文件。
参考
- 曼德尔布罗变焦源代码:https://github.com/cosinekitty/mandelzoom
- LodePNG 首页:https://lodev.org/lodepng
- ffmpeg 项目页面:https://www.ffmpeg.org
在深度学习中只用几行代码就能创造出惊人的图像风格效果!
学习使用 CNN 实现神经类型转移
神经风格转移是一种优化技术,其中将 原始图像 和 风格图像 (如著名画家的艺术品或图案)混合在一起,以获得样式图像的设计或图案中的 输出图像 。换句话说,它也可以被称为图像风格转移。
在本文中,我们将应用 卷积神经网络 (CNN)的深度学习方法来创建一个图像效果,其中一个图像的设计或风格可以应用到另一个图像上,以查看创意效果。



主图像、风格图像和输出图像
上面分享的图片是使用 CNN 实现图像的风格转换的图片。
概述—
对于我们的实验,我们将使用下面的' 原始图像 '和' 风格图像 '分享如下。

原象

风格图像
从上面分享的图片来看,‘原始图片’是我们将应用“ 风格图片 ”的设计得到最终主输出的图片。整个程序的详细代码可以在本文末尾找到。
初始步骤—
在程序代码的初始步骤中,我们将原始图像和样式图像的大小调整为 512X512 。输出大小会是【512,512,3】。其中 3 表示图像是 RGB 或彩色图像。
main_image=main_image.resize((512,512))
style_image=style_image.resize((512,512))main_array=np.asarray(main_image,dtype='float32')
main_array=np.expand_dims(main_array,axis=0)
style_array=np.asarray(style_image,dtype='float32')
style_array=np.expand_dims(style_array,axis=0)
下一步是通过使用expand_dims 将图像整形为形状 (1,512,512,3) 的 4D 张量。然后我们创建一个新的变量' final_image ',这将是我们最终的输出图像。
height=512
width=512
main_image=backend.variable(main_array)
style_image=backend.variable(style_array)
final_image=backend.placeholder((1,height,width,3))input_tensor=backend.concatenate([main_image,style_image,final_image],axis=0)
CNN 架构—
在这种方法中,我们将利用 迁移学习 的概念,应用预先训练好的 VGG16 CNN 模型。
model=VGG16(input_tensor=input_tensor,weights='imagenet', include_top=**False**)

VGG16 架构(来源)
据消息来源强生等人。,为了提取主图像内容层的特征,我们应该选择block1_conv2 ,对于样式层,我们需要选择block1_conv2, block2_conv2, block3_conv3, block4_conv3, block5_conv3。这些层可以准确地从两幅图像中提取特征。
layer_features=layers['block2_conv2']feature_layers = ['block1_conv2', 'block2_conv2',
'block3_conv3', 'block4_conv3',
'block5_conv3']
正如论文中所给出的,所选择的层的组合正确地工作,以获得所需的风格转换。但是,你可以尝试不同的组合,以获得更准确的风格转移。
主要损失—
一旦我们最终确定了 CNN 模型,我们现在可以定义一个主损失函数。这是主图像和我们的输出图像之间的距离。
**def** main_loss(content, combination):
**return** backend.sum(backend.square(content-combination))
风格丧失—
风格损失类似于主损失,因为它是风格图像和我们的输出图像之间的距离。
**def** style_loss(style,combination):
S=gram_matrix(style)
C=gram_matrix(combination)
channels=3
size=height * width
st=backend.sum(backend.square(S - C)) / (4\. * (channels ** 2) * (size ** 2))
**return** st
最终损失—
最后,我们将定义另一个损失,称为最终损失,这将调整最终图像。
**def** final_loss(x):
a=backend.square(x[:,:height-1,:width-1,:]-x[:,1:,:width-1,:])
b = backend.square(x[:, :height-1, :width-1, :] - x[:, :height-1, 1:, :])
**return** backend.sum(backend.pow(a + b, 1.25))
优化—
一旦我们定义了这三种损失,我们可以将风格转换表述为一个优化问题,其中我们的目标是最小化上面定义的所有三种损失,这统称为全局损失。
**def** eval_loss_and_grads(x):
x = x.reshape((1, height, width, 3))
outs = f_outputs([x])
loss_value = outs[0]
grad_values = outs[1].flatten().astype('float64')
**return** loss_value, grad_values
评估员—
在这之后,我们定义了一个类Evaluator(),在这个类中,我们共同组合了上面定义的所有函数,并在主迭代中使用它进行样式转换。
**class** **Evaluator**(object):
**def** __init__(self):
self.loss_value=**None**
self.grads_values=**None**
**def** loss(self, x):
**assert** self.loss_value **is** **None**
loss_value, grad_values = eval_loss_and_grads(x)
self.loss_value = loss_value
self.grad_values = grad_values
**return** self.loss_value **def** grads(self, x):
**assert** self.loss_value **is** **not** **None**
grad_values = np.copy(self.grad_values)
self.loss_value = **None**
self.grad_values = **None**
**return** grad_values
结果—
在这种情况下,我们将使用有限内存 BFGS,这是一种优化算法来执行 10 次迭代的风格转移。
evaluator=Evaluator()
iterations = 10
**for** i **in** range(iterations):
print('Start of iteration -', i)
ta = time.time()
x, min_val, info = fmin_l_bfgs_b(evaluator.loss, x.flatten(),
fprime=evaluator.grads, maxfun=20)
print(min_val)
tb = time.time()
print('Iteration **%d** done in **%d** seconds' % (i, tb - ta))
对可视化结果用L-BFGS算法* 我们得到如下图像。*

最终图像
从上图中,我们可以看到' 样式图像 '的样式已经成功的被施加到' 原始图像 '上。因此,我们成功地实现了使用 CNN 的图像风格转换。
我分享了我的 github 库的链接,在那里你可以找到完整的代码供你参考。
这是一个由代码组成的库,用于执行图像风格转换,以动画的形式显示真实的图像…
github.com](https://github.com/mk-gurucharan/Image-Style-Transfer)
其他例子—
这里有更多的图像风格转换的例子,已经用这个程序实现了。






图像风格转移的示例
结论—
从这篇文章中,我们已经能够利用深度学习,特别是 CNN,来创建惊人的风格转移效果。尝试调整超参数,优化器和其他 CNN 架构,以获得新的和不同的结果。到那时,快乐的机器学习!*
使用 PyTorch 和 Streamlit 创建影像分类 Web 应用程序

LinkedIn 销售导航员在 Unsplash 上的照片
你刚刚开发了一个很酷的 ML 模型。
你以此为荣。您希望通过 web 演示向您的朋友展示它,以便他们可以与您的模型进行交互并提供反馈。
然而,你并不熟悉常见的框架,如 Django 和 Flask 。
你开始问自己:有没有一种方法可以用最少的框架构建一个快速的 web 演示?
古玩目录
概观
在这篇文章中,我将通过一个简单的例子来展示如何使用 Streamlit 来构建一个简单的 web 应用程序。
Streamlit 是一个开源的 Python 库,可以轻松构建用于机器学习和数据科学的定制 web 应用[1]。点击查看它的图库来看看其他人创建的一些应用程序。
我在这里选择图像分类作为一个例子,因为计算机视觉(CV)是目前人工智能中最受欢迎的领域之一,由深度学习算法驱动。它还有广泛的应用,比如对医学图像进行分类,帮助医生进行疾病诊断[2]。在这里了解更多关于深度学习模型的图像分类。
出于演示的目的,我将使用 PyTorch 的预训练 ResNet 模型,对于相同的任务,您可以随时使用其他库(TensorFlow、Keras 等)。),其他架构,甚至定制自己的模型。
要查看我的完整 Python 代码,请查看我的 Github 页面。
现在事不宜迟,让我们开始吧!
安装 Streamlit
第一步是安装 Streamlit 库,您可以使用 pip 命令来完成。我建议您使用 Python 虚拟环境来分别保存每个项目的依赖关系。
$ pip install streamlit
成功安装后,您可以使用一个简单的“Hello World”应用程序进行快速检查:
$ streamlit hello
用户界面
对于我们的应用程序,一个关键要素是使用户能够为模型上传图像以进行预测,这可以通过' file_uploader '函数来完成:
import streamlit as st
file_up = st.file_uploader("Upload an image", type="jpg")
请确保指定适当的文件类型,以便它能与分类模型一起正常工作。
然后我们可以显示这个图像:
from PIL import Image
image = Image.open(file_up)
st.image(image, caption='Uploaded Image.', use_column_width=True)
除此之外,我们还将使用“set_title”为应用程序创建一个标题,并使用“write”显示预测结果。
分类模型
要使用 PyTorch 的预训练模型,请确保安装了“Torch”和“torchvision”库。现在我们可以创建一个 ResNet 模型:
from torchvision import models, transforms
import torch
resnet = models.resnet101(pretrained=True)
简单来说,残差网络(ResNet)是一种改进的卷积神经元网络(CNN),在知名的 ImageNet 数据库中训练,在图像分类、物体检测等 CV 任务中取得了的优异性能。这个特殊的模型“resnet101”意味着它有 101 层(深!).点击阅读更多关于 ResNet 及其变种的信息。
在我们创建这个模型之后,我们需要通过调整大小、标准化等来转换输入图像。这里我们利用了“火炬视觉”中的“变换”模块:
transform = transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize(
mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225]
)])
注意,图像根据其平均值和标准偏差进行归一化。详见文档。
现在,我们能够加载图像、预处理图像并进行预测:
img = Image.open(image_path)
batch_t = torch.unsqueeze(transform(img), 0)resnet.eval()
out = resnet(batch_t)
接下来,我们可以返回按最高概率排序的前 5 个预测。确保 ImageNet 中 1000 个类别的名称可用,以便我们可以通过索引输出预测:
prob = torch.nn.functional.softmax(out, dim=1)[0] * 100
_, indices = torch.sort(out, descending=True)
return [(classes[idx], prob[idx].item()) for idx in indices[0][:5]]
结果
现在,我们可以通过在命令提示符/终端中键入“streamlit run
第一个例子:

太好了!金毛位居榜首,置信度很高(~97)。
让我们试试另一个例子:

青蛇高居榜首!再次,它的置信度得分相当高。
这里需要注意的一点是,由于该模型是在 ImageNet 上训练的,因此对于 1000 个类别之外的图像,它的性能可能没有那么好。
后续步骤
创建 web 应用程序后,下一步自然是部署和托管它。例如,我通过 Heroku 部署了一个虹膜分类应用程序,你可以通过这个 Github 页面查看。
此外,如果你对其他神经网络模型感兴趣(VGG,Densenet 等。),你可以尝试上传不同的图像,然后比较它们的性能。
摘要
让我们快速回顾一下。
我们通过 Streamlit 构建了一个简单的 web 应用程序,在这个应用程序中,用户可以上传图像来查看模型的顶级预测以及置信度得分。我们还介绍了如何通过 PyTorch 构建预训练 ResNet 模型。
我希望你喜欢这篇博文,并请分享你的任何想法:)
看看我的另一篇关于使用逻辑回归对 Yelp 评论进行情感分类的文章:
情感分析:特征提取、N-gram、过采样/欠采样、TF-IDF 等等…
towardsdatascience.com](/sentiment-classification-with-logistic-regression-analyzing-yelp-reviews-3981678c3b44)
参考
【1】https://docs.streamlit.io/en/stable/
【2】https://www.hindawi.com/journals/cin/2018/2061516/
使用 Matplotlib 创建信息图

君提供的信息图
2019 年澳大利亚城市的温度模式
从我之前关于 [matplotlib](/plt-xxx-or-ax-xxx-that-is-the-question-in-matplotlib-8580acf42f44) 绘制的层次结构和实例化 [axes](/the-many-ways-to-call-axes-in-matplotlib-2667a7b06e06)的多种方式的帖子中,我们可以看到这些特性赋予了matplotlib创造高度复杂和可定制可视化的巨大潜力。为了证明这一点,也为了提高我自己对matplotlib的理解,本周我开始用matplotlib制作一个信息图。
一个信息图通常将视觉图像、数据图表和最少的文本结合在一起。它旨在说明一个主题的易于理解的概述。由于这种性质,与常规静态数据图相比,其布局和内容更加复杂多样,常规静态数据图通常在一种类型的图中显示一种类型的数据(如条形图、散点图、折线图和盒图或 及其变体 )。此外,信息图可以是一个独立的图,而常规的静态数据图主要作为补充材料,应该在一定的背景下阅读。
你可能已经从标题图中看到了完整的信息图,它显示了 2019 年澳大利亚八个主要城市的每日最高温度和降水量的年度模式(),我真的希望你在阅读这一段之前能了解它的主题。这让我对继续前进充满信心。我的信息图的灵感来自《南华早报》的这张信息图。
我个人非常喜欢将大量数据可视化为网格状结构。当颜色和形状设置得当时(高温时为砖红色,低温时为北极冰蓝色,我的例子是),它开始传达错综复杂背后的图案(如纬度降低时北极冰蓝色减少),同时也传递了一种艺术感(如一串红色条的外观看起来像燃烧的木头)。
好了,事不宜迟,现在让我们深入代码,向您展示我是如何使用matplotlib创建这个信息图的。像往常一样,你可以从 my Github 访问所有需要的数据和 jupyter 笔记本。
定义目标并收集数据
尽管这不在本文的讨论范围之内,我还是列出了这一部分来强调这是制作有效信息图的基础部分。只有你知道要讲什么故事,你才有收集数据和思考设计、布局、图表和美学的方向。至于我们的例子,天气数据是从澳大利亚气象局网站下载的。我们只需要日最高气温、城市名称和日期值(即max _ tmp _ day、 城市 、 日期 如图 1 )。

图 1 |数据处理
布局
正如我在之前的帖子中所说,fig.add_axes([left, bottom, width, height])是手动将axes放置在fig上的好方法。然而,当我们有许多axes ( 我们总共有 18 个 *axes* )并且需要对齐(我们的眼睛非常挑剔,即使轻微的错位也会使事情失去平衡)时,精确计算fig上每个axes的坐标是繁琐的。我于是采用了普通布局和任意布局axes的fig的混合。使用fig.add_gridspec()和fig.add_axes()。这里,fig.add_gridspec()是一个函数,它使我们能够指定将放置axes的网格的几何形状。例如,想象一个 2 行 2 列的网格在一个fig上,通常如果我们使用fig.subplots(nrows=2, ncols=2),这将产生 4 个axes均匀分布在 2×2 的网格上。如果在 2 乘 2 的网格上,我们只需要 3 个axes,第一个axes占据整个第一行,而剩余的 2 个axes平均占据第二行,会怎么样?这里有了fig.add_gridspec()的力量,它使我们能够根据需要创建axes跨越的行和列。我们可以实现上述布局如下:
fig = plt.figure()# Use GridSpec for customising layout
gs = fig.add_gridspec(nrows=2, ncols=2)# Add an empty axes that occupied the whole first row
ax1 = fig.add_subplot(gs[0, 0:2])# Add two empty axes that occupied the remaining grid
ax2 = fig.add_subplot(gs[1, 0])
ax3 = fig.add_subplot(gs[1, 1])
正如你所看到的,一旦一个网格空间对象(即 *gs*)被创建,我们可以利用它的网格几何,就像从一个 2D numpy.ndarray中访问值一样,来相应地放置axes。例如,fig.add_subplot(gs[0, 0:2])表示添加一个axes占据 2×2 网格中的整个第一行。
信息图表布局的代码
回到信息图,如上面的代码所示,除了ax2 ( 色条的轴)外,其他的axes都是由fig.add_gridspec(nrows=10, ncols=10)添加的。具体来说,在一个 10 行 10 列的网格上(图 2),ax1,也就是标题、文本和注释的axes,占据了前 2 行 8 列。从ax3到ax10的每一个axes都是绘制温度条的axes,占据 1 行 8 列。最后,从ax11到ax18的每一个axes,也就是雨量数据的axes,只占 1 行 2 列。

图 2 |信息图布局
如你所见,当同时需要多个axes的灵活性和一致性时,fig.add_gridspec()是一个强大的功能。
内容和配色方案
布局确认后,我们可以添加数据图。这里以温度条为例(图 3)。

图 3 |条形图示例
考虑到信息和美观,每个条形代表这八个主要城市的日最高温度和年平均温度(24.43 摄氏度)之间的差值。这样,观众可以清楚地识别出高于平均气温的日子(条向上)和低于平均气温的日子(条向下)。否则,由于温度值是正的,所有的条形图将在零度以上朝向相同的方向,这使得条形图很无聊。此外,与常规的条形图不同,我删除了所有的网格、x 轴和 y 轴,只留下了必要的部分。
另一个附加功能是带有弯曲箭头的文本注释,分别指出最高和最低温度的日期。从美学的角度来看,这给整个信息图增加了灵活性。这是由ax.annotate()交付的。关于ax.annotate()的官方文档已经给出了非常详细的例子,所以本帖不再重复该功能的介绍。
由于这八个城市的温度柱状图的样式需要保持一致,我们只需要为一个柱状图生成代码,并通过for loop添加其他柱状图(见下面的代码)。
条形图的代码
虽然配色方案是一个非常主观的决定,但我可以在这里分享我遵循的原则:创造对比、分组元素、编码数量。在这张信息图中,我使用了深色背景来突出温度柱状图和降雨圈。黑色的背景也表达了一种阴郁的气氛,以反映极端天气的紧急情况。此外,条形图和雨量圈分别使用一致的颜色,有助于将信息组织在一起。最后,不同温度值的色谱应用(从北极冰蓝色到砖红色)突出了图案。
标题、文本和注释
信息图可以是一个独立的图的原因是必要的文字有助于加强其主题。这里我们可以使用ax.text()将任何文本放在fig上我们想要的任何地方。我发现的唯一缺陷是给matplotlib添加一个自定义字体家族有点麻烦(一解此处)。另一种方法是在信息图主体完成后通过 Illustrator 添加文本,并导出为svg文件。
和往常一样,我欢迎反馈、建设性的批评以及听到关于您的数据科学项目的信息。可以通过 Linkedin 和我的网站找到我。
使用 R 创建一个交互式的新冠肺炎报告,免费托管并自动更新
引人入胜的可视化,闪亮的用户界面和 GitHub 操作,创造完美的报告!
本帖是 第一部分 一系列 4 期刊物 。请参考 第 1 部分 了解系列概述, 第 2 部分 了解数据源和次要数据清理, 第 3 部分 了解可视化的创建,构建报告以及将文档部署到 ShinyApps.io 和 【项目回购】
每篇文章都是独立的,意思是你真的不需要阅读其他部分来充分利用它。

交互式报告的导航
自 2020 年 3 月以来,所有新闻媒体和政府机构一直在用新冠肺炎的统计数据和图表轰炸民众。这篇由 Tomas Pueyo 撰写的中型文章于 3 月初发表,是首批深度探索 COVID 数据的文章之一,揭示了许多见解,并在短短几天内获得了数千万次浏览。美国约翰·霍普斯金大学也提供了一个非常有用的仪表板以及他们的数据每天更新。他们的数据结合了多个来源,如世卫组织、美国疾病传播中心(CDC)和欧盟 CDC 等。
早期,互联网上充斥着大量来自大学的报告。我意识到我无法制作世界级的仪表板或报告,但至少我想制作自己的仪表板或报告,并学习如何制作。
目录
导语
ggplot,Plotly and Shiny
数据来源
计划
后会有期!
戏弄者
在我们开始之前,我想让你看看最终产品会是什么样子。我们将最终得到一个交互式的基于云的 HTML 报告(有一个闪亮的后端),显示不同的 COVID19 相关图。您可以通过以下链接与最终报告互动→https://lucha6.shinyapps.io/covideda/
我们将制作以下(互动)情节,并将它们烘焙成一个漂亮的互动 RMarkdown 文档,每天更新,无需我们做任何额外的工作。
按国家、洲和全球 COVID 显示死亡人数的树形图
显示一段时间内各大洲累计病例数的折线图

样本 R(闪亮)代码和显示单张地图的输出,其中国家由确诊病例数着色
ggplot、神秘而闪亮
在我看来是最好的绘图库。这个库基于 Leland Wilkinson 的 Grammar of Graphics(GoG),作为一个 R 包来实现和发布。我推荐阅读原文 [ggplot](https://byrneslab.net/classes/biol607/readings/wickham_layered-grammar.pdf) 2010 年论文由全能的 Hadley Wickham 关于ggplot的第一次实现和由 Dipanjan (DJ) Sarkar 关于 GoG 背后理论的全面而简明的指南。
Plotly 是一个很棒的跨语言库(最初是用 JavaScript 编写的),允许制作交互式图形。在 R 语言中,也就是我们今天要用的语言,他们有一个叫做ggplotly()的函数,可以让你把任何ggplot的情节变成一个没有开销的情节。
闪亮的让 R 用户无需了解一点 JavaScript 或 HTML 就能制作出漂亮的仪表板和交互式报告,所有这些都只需要 R。 RStudio 还为每位用户提供多达 5 个免费仪表盘网站,这是一种无摩擦的方式来构建您的第一个仪表盘、网络应用或交互式 R 笔记本。
数据源
当我在三月份开始这个项目时,我开始使用的数据源来自 Kaggle:由用户 SKR 上传和维护的新型冠状病毒数据集。如数据集描述中所述,这只是 JHU 数据集的镜像,GitHub 中也有数据集。不幸的是,在项目后期,我发现这个数据源中有几个工件。例如,在西班牙,4 月 24 日报告了-10000 例确诊病例,5 月 25 日记录了-2000 例死亡,正如本期 GitHub中讨论的(在 JHU 资料库的 1300 多个未决问题中)。数据中还出现了类似的其他问题,而事实上,存储库维护者并没有站出来对此做出解释,这让我对这些数据的使用产生了怀疑。此外,来自谷歌或我们的数据世界(OWiD)的 COVID 每日案例没有显示这些人工制品。
我决定将我的数据源从 JHU 中切换出来,改用 OWiD。令我非常满意的是,OWiD 数据非常干净,充满了预先计算的特性和统计数据(比如测试统计数据、人口统计数据、每个国家的预期寿命……)。
计划
我认为这个项目对于一篇文章来说太大了,因此我决定写一个 4 部分的系列(包括这个介绍)。接下来的三篇文章如下:
- 我们将首先涵盖数据清理,这是一个必要的步骤,使我们的每个后续情节。我们主要关注每日和累计的死亡和确诊病例数。这并不令人兴奋或有足够的洞察力来写一篇关于它的中型文章,因此我为那些对 RPubs 感兴趣的人发布了这个步骤(在这里阅读)。你也可以在另一个 RPubs 笔记本中探索我清理和争论 JHU 数据的努力。出于学习的目的,我在第二个笔记本上的努力要有用得多。数据清理是极其重要的一步,但由于它并不花哨,所以经常被忽视。尽管如此,所有的数据科学家都应该熟悉它。
- 接下来,我们将使用
ggplot2,plotly和leaflet制作每个图,并学习如何制作和部署一个闪亮的 RMarkdown 文档。我们还将看到如何将plotly图存储为常规文件,以加速我们闪亮文档的加载。 - 最后,我们将编写自动化工具(bash 脚本和 Github 动作),这样我们的报告就可以每天更新,而不需要我们做任何额外的工作。
回头见!
在 Power BI 中创建 N 元排序
数据科学/电力 BI 可视化
关于构建 Python 可视化的快速入门指南,只需点击几下鼠标和少量代码。

在之前的一篇 文章 中,我写了一篇关于使用 nltk 进行自然语言处理来创建和可视化 n-gram 排序的快速入门指南。然而,我需要一种方法来与那些机器上没有安装 Python 或 Jupyter Notebook 的人分享我的发现。我需要使用我们组织的 BI 报告工具:Power BI。
进入 Python 可视化。
Python 可视化允许您创建通过运行 Python 代码生成的可视化。在本帖中,我们将使用这种视觉效果来展示我们的 n-gram 排序结果所需的步骤。
首先,让我们得到我们的数据。你可以在这里下载样本数据集。然后,我们可以将数据加载到 Power BI Desktop 中,如下所示:

选择文本/CSV 并点击“连接”。

在 Windows 资源管理器文件夹中选择文件,然后单击打开:

点击“加载”。

接下来,在“可视化”面板上找到 Py 图标。

然后,在出现启用脚本视觉效果的提示时,单击“启用”。

您将看到一个占位符出现在主区域,一个 Python 脚本编辑器面板出现在仪表盘的底部。

选择“字段”面板上的“文本”栏。

您将看到一个预定义的脚本,它是我们将要编写的脚本的序言。

在 Python 脚本编辑器面板中,将光标放在第 6 行的末尾,然后按两次 enter 键。
然后,复制并粘贴以下代码:
import re
import unicodedata
import nltk
from nltk.corpus import stopwordsADDITIONAL_STOPWORDS = ['covfefe']import matplotlib.pyplot as pltdef basic_clean(text):
wnl = nltk.stem.WordNetLemmatizer()
stopwords = nltk.corpus.stopwords.words('english') + ADDITIONAL_STOPWORDS
text = (unicodedata.normalize('NFKD', text)
.encode('ascii', 'ignore')
.decode('utf-8', 'ignore')
.lower())
words = re.sub(r'[^\w\s]', '', text).split()
return [wnl.lemmatize(word) for word in words if word not in stopwords]words = basic_clean(''.join(str(dataset['text'].tolist())))bigrams_series = (pandas.Series(nltk.ngrams(words, 2)).value_counts())[:12]bigrams_series.sort_values().plot.barh(color='blue', width=.9, figsize=(12, 8))plt.show()
简而言之,上面转换的代码从dataset数据帧的'text'列中提取 n-grams,并使用 matplotlib 创建一个水平条形图。plt.show()的结果就是 Power BI 在 Python 可视界面上显示的内容。
关于这段代码的更多信息,请访问我的以前的教程。
使用 nltk 为自然语言处理创建和可视化 n 元语法排序的快速入门指南。
towardsdatascience.com](/from-dataframe-to-n-grams-e34e29df3460)
粘贴完代码后,单击 Python 脚本编辑器面板右上角的“播放”图标。

几分钟后,您应该能够看到如下所示的水平条形图:

就是这样!
只需简单地点击几下鼠标,在 Python 脚本的帮助下,我们就能够可视化 n 元语法排序的结果。
我希望你喜欢今天关于 Power BI 最强特性之一的帖子。Power BI 已经有了一些有用和漂亮的内置视觉效果,但有时,你只需要多一点灵活性。运行 Python 代码对此有所帮助。我希望这个温和的介绍将鼓励你探索更多,扩大你的剧目。
在下一篇文章中,我将分享一个使用 spaCy 从熊猫数据帧中提取命名实体的快速入门指南 。
敬请期待!
用 Java 创建一个有序的 JSONObject
为什么创建有序 JSONObject 这么复杂?

米歇尔·亨德森在 Unsplash 上的照片
在 Java 中使用 JSONObject 时,您可能会注意到,当您打印出对象时,顺序并不完全是您所期望的。
我们要做的就是把它改成订购的,对吗?
嗯,事情比这要复杂一点,幸运的是,我已经找到了这个常见问题的迷人解决方案。
在这种情况下,我们进入幕后,操纵底层的数据结构,使之成为我们所需要的。
我将首先解释这个问题,然后给你提供一个解决方案。然后,我们将讨论您处理此问题的其他方式。
我们开始吧!
问题是
JSONObject 的底层数据结构是 HashMap。为什么?HashMap 允许快速检索键值对,使它们成为 JSON 对象的完美数据结构。
但是,正如我们在数据结构和算法课程中所记得的,默认情况下,HashMaps 是无序的,这意味着您的数据是随机分布在内存中的。
这意味着,如果我们想在日志、浏览器或电子邮件中打印 JSONObject,顺序可能会显得不规则。
这里有一个例子,我们用四个元素创建了一个 JSONObject。请注意我们向 JSONObject 添加对象的顺序:
现在看看这些对象在我们的日志中是如何显示的:

顺序应该是“一”、“二”、“三”、“四”。
如果我们以特定的顺序期待我们的结果,这是不好的。
解决方案
有几种方法可以处理这个问题,但是我将挖掘一个我非常感兴趣的解决方案。
我们将利用我以前只在单元测试中使用过的 API:反射。
反射是一个运行时 API,用于修改方法、接口和类的行为。这是一个很好的工具,我们可以用它来改变“幕后”的代码。
如果你看一下JSONObject.class,你会看到这个构造函数:

这是创建 JSONObject 的默认构造函数。我们必须将底层数据结构(HashMap)改为有序的。对此的完美解决方案是 LinkedHashMap。
现在,让我们一行一行地检查这段代码:
- 第 14 行:我们仍然在创建之前使用过的 JSONObject。
- 第 15 行:我们需要处理这些方法抛出的异常(
IllegalAccessException和NoSuchFieldException)。因此,我们使用一个 try-catch 块。 - 第 16 行:Field 是我前面提到的反射 API 中的一个类。这有助于我们访问 JSONObject 类中声明的“map”字段。我们创造了一个“反射物体”
- 第 17 行:在上面 JSONObject.class 的截图中你可能已经注意到了,
nameValuePairs变量是私有的。我们需要让它变得容易接近。 - 第 18 行:既然变量是可访问的,我们可以将
HashMap<>()改为LinkedHashMap<>()。 - 第 19 行:出于安全考虑,我们将把该变量的可访问性设置回 false。
将这个 JSONObject 记录到控制台后,您会看到输出现在是有序的:

大获成功!
替代解决方案
这肯定不是解决这个问题的唯一办法。这只是我感兴趣的一个解决方案,并且被证明是有效的。
还有其他库可以用来构建 JSON 对象,它们很可能提供对有序 JSON 的支持;然而,这是我使用org.json.JSONObject的一个要求,所以我决定为这个 JSON 对象找到一个解决方案。
JSONArrays 可能会提供您正在寻找的解决方案,因为订单遵循一个索引。
一个可能的解决方案是实现您自己的 JSONObject。您可以使用 LinkedHashMap <>()或其他有序的数据结构,而不是使用 HashMap <>()来实现。
如何解决这个问题的机会是无限的,但是使用反射 API 是一个很棒的选择。
如果您有任何问题、意见或顾虑,请告诉我!
使用 Python 的 Matplotlib 创建和定制箱线图,以从数据中获得大量见解

箱线图被低估了。它们塞满了关于底层分布的见解,因为它们将大量关于数据的信息浓缩到一个小的可视化中。
在本文中,您将看到箱线图如何成为实现以下目标的强大工具:
- 了解数据的分布。
- 发现异常值。
- 比较分布,以及箱线图可视化中的小调整如何更容易发现分布之间的差异。
了解数据的分布
在探索性数据分析过程中,箱线图是直方图的一个很好的补充。
使用直方图,很容易看到分布的形状和趋势。因为直方图突出了每个数据点在分布中出现的频率。
箱线图不直接关注频率,而是关注分布中的值的范围。

直方图突出显示频率,而箱线图突出显示数据的范围。
我们习惯用频率和比较比例来思考。这就是为什么我们如此轻松地解释直方图的洞察力,在直方图中,我们可以发现大多数数据集中的值,我们可以看到分布的形状。
使用箱线图,我们可以获得与直方图相同的洞察力。虽然我们可以用直方图来显示分布的形状,但箱线图突出显示了给出分布形状的汇总指标。我们可以从箱线图中提取的汇总指标有:
- 分位数,特别是第一和第三分位数,对应于第 25 和第 75 个百分点。
- 中位数,分布的中间点,也对应于第 50 个百分位数。
- 四分位数范围(IQR) ,第三个和第一个分位数之间的宽度。用数学表达,我们有 IQR = Q3 — Q1。
- 最小值,数据集中排除异常值的最小值,对应于 Q1-1.5 倍质量分数
- Max ,数据集中的最大值,不包括异常值,对应 Q3+ 1.5xIQR。

您可以从直方图和箱线图中提取的汇总指标。
斑点异常值

突出异常值的箱线图。
在方框图中显示异常值通常显示为圆圈。但是正如您将在下一节看到的,您可以定制离群值的表示方式😀
如果你的数据集有异常值,用箱线图很容易发现它们。有不同的方法来确定数据点是异常值。最广为人知的是 1.5xIQR 规则。
1.5xIQR 规则
异常值是数据集中的极端观察值。因此,判断一个数据点是否极端的经验法则是将其与四分位间距进行比较。
使用四分位距(IQR)来发现异常值是有意义的。IQR 是第一个和第三个四分位数之间的值范围,即第 25 个和第 75 个百分位数,因此它将包括数据集中的大多数数据点。
但是为什么是 1.5 倍的四分位间距呢?这与被称为68–95–99 规则的正态分布的一个重要特征有关。

68–95–99 法则,来源:【https://commons.wikimedia.org/wiki/File:Empirical_Rule.PNG
根据 68–95–99 规则,我们知道:
- 68%的数据在平均值之上或之下的一个标准偏差内,
- 95%的数据在平均值的两个标准偏差内,
- 99.7%的数据在平均值的三个标准偏差之内。
只有很少的数据点会超过平均值的三个标准偏差,更准确地说,只有 0.3%的数据点。所以任何超过三个标准差的数据点都被认为是极端的。
为了检查一个数据点是否是异常值,并检查它是否超出三个标准差,我们计算:
- Q1-1.5 倍
- Q3 + 1.5xIQR。
这些代表分布中不被认为是极端的区域的下限和上限。其最终大约是平均值的 3 个标准偏差。
乘数是 1.5,因为任何大于 1.5 的数字都会导致大于 3 倍标准差的范围。因此,数学家们选定了一个中间数。

箱线图和概率密度函数,来源:https://commons.wikimedia.org/wiki/File:Boxplot_vs_PDF.svg
任何低于下限或高于上限的数据点都是异常值;
- (数据点值)< Q1–1.5xIQR, then it’s an outlier.
- (data point value) > Q3 + 1.5xIQR,那么就是离群值。
自定义箱线图以比较分布
箱线图也是比较不同分布的好工具。
让我们比较一下虹膜数据集中花朵花瓣长度的分布。

比较虹膜数据集的花瓣长度。
以下是你如何创建这个情节。
import numpy as np
import pandas as pd
from sklearn import datasets
import matplotlib.pyplot as plt# Load Iris dataset
iris = datasets.load_iris()# Preparing Iris dataset
iris_data = pd.DataFrame(data=iris.data, columns=['sepal_length', 'sepal_width', 'petal_length', 'petal_width'])iris_target = pd.DataFrame(data=iris.target, columns=['species'])
iris_df = pd.concat([iris_data, iris_target], axis=1)# Add species name
iris_df['species_name'] = np.where(iris_df['species'] == 0, 'Setosa', None)iris_df['species_name'] = np.where(iris_df['species'] == 1, 'Versicolor', iris_df['species_name'])iris_df['species_name'] = np.where(iris_df['species'] == 2, 'Virginica', iris_df['species_name']) # Prepare petal length by species datasets
setosa_petal_length = iris_df[iris_df['species_name'] == 'Setosa']['petal_length']versicolor_petal_length = iris_df[iris_df['species_name'] == 'Versicolor']['petal_length']virginica_petal_length = iris_df[iris_df['species_name'] == 'Virginica']['petal_length'] # Visualize petal length distribution for all speciesfig, ax = plt.subplots(figsize=(12, 7))# Remove top and right border
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)# Remove y-axis tick marks
ax.yaxis.set_ticks_position('none')# Add major gridlines in the y-axis
ax.grid(color='grey', axis='y', linestyle='-', linewidth=0.25, alpha=0.5)# Set plot title
ax.set_title('Distribution of petal length by species')# Set species names as labels for the boxplot
dataset = [setosa_petal_length, versicolor_petal_length, virginica_petal_length]labels = iris_df['species_name'].unique()
ax.boxplot(dataset, labels=labels)plt.show()

(再次)比较虹膜数据集的花瓣长度。
我们可以从这个情节中获得一些启示:
- 刚毛鸢尾的花瓣长度远小于杂色鸢尾和海滨鸢尾。它的范围从大约 1 到 2 厘米。
- 海滨鸢尾的花瓣长度范围大于刚毛鸢尾和杂色鸢尾的花瓣长度范围。我们可以从**的高度看出,与其他两个相比,海滨鸢尾的盒子是的。
- 鸢尾和 Veriscolor 都有异常值。
我们还可以通过查看每个分布的汇总指标来确认这些见解。

鸢尾属植物花瓣长度的综合度量。
下面是计算这些指标的方法。
*def get_summary_statistics(dataset):
mean = np.round(np.mean(dataset), 2)
median = np.round(np.median(dataset), 2)
min_value = np.round(dataset.min(), 2)
max_value = np.round(dataset.max(), 2) quartile_1 = np.round(dataset.quantile(0.25), 2)
quartile_3 = np.round(dataset.quantile(0.75), 2) # Interquartile range
iqr = np.round(quartile_3 - quartile_1, 2) print('Min: %s' % min_value)
print('Mean: %s' % mean)
print('Max: %s' % max_value)
print('25th percentile: %s' % quartile_1)
print('Median: %s' % median)
print('75th percentile: %s' % quartile_3)
print('Interquartile range (IQR): %s' % iqr)
print('Setosa summary statistics')print('\n\nSetosa summary statistics')
get_summary_statistics(setosa_petal_length)print('\n\nVersicolor summary statistics')
get_summary_statistics(versicolor_petal_length)print('\n\nVirginica summary statistics')
get_summary_statistics(virginica_petal_length)*
定制您的箱线图
乍一看,很难区分不同物种的箱线图。底部的标签是我们比较分布的唯一视觉线索。
我们可以使用 boxplot 的属性来定制每个框。由于属性应用于所有数据,这些数据是给定 boxplot 方法的,我们不能采用最后一个绘图的方法,并使用每个物种花瓣长度的数组作为输入。**
我们必须绘制每个物种的花瓣长度,并对每个物种应用属性。
我们将使用以下参数:
- **位置:箱线图在绘图区的位置。我们不想将每个物种的箱线图绘制在彼此之上,所以我们用它来设置每个箱线图在 x 轴上的位置。
- medianprops :应用于箱线图内中线的属性字典。
- whiskerprops :应用于胡须的属性字典。
- capprops :应用于胡须上帽子的属性字典。
- flierprops :应用于离群值的属性字典。
我们还可以自定义其他几个属性。在本例中,我将为每个箱线图添加不同的颜色,这样更容易看到我们在可视化不同的分布。

比较虹膜数据集的花瓣长度,为每个物种定制颜色。
*fig, ax = plt.subplots(figsize=(12, 7))# Remove top and right border
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)# Remove y-axis tick marks
ax.yaxis.set_ticks_position('none') # Set plot title
ax.set_title('Distribution of petal length by species')# Add major gridlines in the y-axis
ax.grid(color='grey', axis='y', linestyle='-', linewidth=0.25, alpha=0.5)# Set species names as labels for the boxplot
dataset = [setosa_petal_length, versicolor_petal_length, virginica_petal_length]
labels = iris_df['species_name'].unique() # Set the colors for each distribution
colors = ['#73020C', '#426A8C', '#D94D1A']
colors_setosa = dict(color=colors[0])
colors_versicolor = dict(color=colors[1])
colors_virginica = dict(color=colors[2])# We want to apply different properties to each species, so we're going to plot one boxplot
# for each species and set their properties individually
# positions: position of the boxplot in the plot area
# medianprops: dictionary of properties applied to median line
# whiskerprops: dictionary of properties applied to the whiskers
# capprops: dictionary of properties applied to the caps on the whiskers
# flierprops: dictionary of properties applied to outliersax.boxplot(dataset[0], positions=[1], labels=[labels[0]], boxprops=colors_setosa, medianprops=colors_setosa, whiskerprops=colors_setosa, capprops=colors_setosa, flierprops=dict(markeredgecolor=colors[0]))ax.boxplot(dataset[1], positions=[2], labels=[labels[1]], boxprops=colors_versicolor, medianprops=colors_versicolor, whiskerprops=colors_versicolor, capprops=colors_versicolor, flierprops=dict(markeredgecolor=colors[1]))ax.boxplot(dataset[2], positions=[3], labels=[labels[2]], boxprops=colors_virginica, medianprops=colors_virginica, whiskerprops=colors_virginica, capprops=colors_virginica, flierprops=dict(markeredgecolor=colors[2]))plt.show()*
就是这样!您可以使用箱线图来探索您的数据和自定义您的可视化,以便更容易提取见解。
感谢阅读!
在 1 分钟内创建并共享交互式地图
使用 Google Sheet 创建交互式 Choropleth 地图的简单方法。

由 Puk Patrick 在 Unsplash 上拍摄的照片
在数据科学中,在你完成数据分析后,你可能需要用一些漂亮的交互式数据可视化工具来探索或展示结果。当然,这些工具中的一个将包括交互式地图,您可以将鼠标放在该区域并探索数据值。但是,这个过程需要花费很多时间去学习和实践。
本文将向您展示一种替代方法,让您在 1 分钟内使用 Google Sheets 从数据集创建交互式地图。作为一个例子,本文通过创建一个交互式地图来探索每个国家的新冠肺炎数据集,用户可以悬停在该地图上并查看已确认的新冠肺炎病例数。

互动地图显示截至 2020 年 10 月 21 日确诊的新冠肺炎病例。(作者)
我们开始吧!
第一步:把你的数据集放在谷歌表上。
在这第一步,你只需要打开谷歌表单(https://docs.google.com/spreadsheets)。然后,从 CSV、Excel、Html 等格式导入您的数据。或者你甚至可以将你的数据复制粘贴到谷歌工作表中。作为下面的例子,我使用了已确认的新冠肺炎案例数据集**。

使用 Google Sheet 创建地理图。(作者)
该数据集是使用 Google Big Query 从 JHU-CSSE 查询和汇总的新冠肺炎数据。如果你想知道它是如何做到的,请查看我的教程 这里 。
第二步:创建一个交互式地图。
要创建交互式地图,只需点击插入>图表。

使用 Google Sheet 创建地理图。(作者)
将图表导入工作表后,只需找到“地图”类别并选择“地理图表”图表类型。

使用 Google Sheet 创建地理图。(作者)
然后,您可以进行一些最终设置,如自定义地图风格,背景颜色,字体等。

在 Google Sheet 上定制地图样式。(作者)
祝贺你,现在你在谷歌工作表中有了一个漂亮的交互式地图!
第三步:分享地图。
地图制作完成后,您可以轻松地与同事分享 Google Sheet。或者,您也可以通过单击地图右上角的菜单,然后单击“发布图表”,将最终地图嵌入到您的网站中。

从 Google Sheet 发布图表。(作者)
差不多就是这样!我希望你喜欢这篇文章,并能够使用 Google Sheet 以有效的方式用地图可视化数据。 平安健康!
感谢阅读。👋😄
用 Python 创建自动更正!
nltk 包装笼简介

马库斯·斯皮斯克在 Unsplash 上的照片
T 他的文章将指导你用 python 创建一个简单的自动更正程序。这个项目是创建两个不同的拼写推荐器,它将能够接受用户的输入,并推荐一个正确拼写的单词。非常酷!
注意:测试输入:['cormulent ',' incendenece ',' validrate']。
包装
这项工作将主要集中在 nltk 库的使用上。nltk 代表自然语言工具包,关于它能做什么的更多信息可以在这里找到。
具体来说,我们将使用单词、edit_distance、jaccard_distance 和 ngrams 对象。
edit_distance,jaccard_distance 指的是用于确定与用户输入最相似的单词的度量
一个 n-gram 是来自给定文本或语音样本的 n 个项目的连续序列。例如:“白宫”是一个二元结构,与“白宫”有着不同的含义。
此外,我们还将使用 pandas 来创建正确单词列表的索引系列。
words.words() 给出了一个拼写正确的单词列表,这些单词已经作为 word 对象包含在 nltk 库中。 spellings_series 是这些单词的索引序列,输出显示在代码块下面。

拼写 _ 系列输出
推荐者 1
度量:Jaccard 距离
这是一种衡量两组有多么不同的方法,我试图用简单的英语解释如下:
正在讨论的字符串将与 spellings_series 中的每个单词进行迭代比较。
对于每个比较实例,我们计算非唯一字母的总数以及两个集合之间共享字母的数量,作为总数和非唯一。然后,我们将非唯一除以总计,并乘以 100%以获得相似度百分比。这是 Jaccard 指数。
Jaccard 距离是对不同的两个集合如何的度量,并且可以作为 Jaccard 索引(即 Jaccard 距离= 100% - Jaccard 指数)
定义一个 Jaccard 函数来遍历可能的单词:
我们将使用一个空列表和一个 for 循环来迭代遍历 spellings_series 。
jaccard 函数将接受参数条目和 gram_number ,其中条目指的是有问题的单词,而 gram_number 设置要使用的 n-gram 的数量(为使用属于同一个 ngram 的单词列表的情况做准备)在这里可以找到关于 ngrams 的更多信息,我花了一些时间来完全理解它!
拼写将根据输入字符串的首字母创建一个可能的单词列表。这里假设第一个字母没有打错。
接下来,距离将使用内置的 jaccard_distance 函数迭代计算拼写中单词各自的 jaccard 距离。
最后,最接近的将通过距离上的最小函数给出最终的最佳匹配单词。这可以被附加到结果空列表中,该列表将被返回。
现在,通过我们令人惊叹的新 jaccard 函数,我们可以创建单词 recommender, JDreco 。默认情况下,该函数将接受字符串列表“cormulent”、“incidence”、“validrate”,并返回建议的单词列表。
恭喜,第一个推荐模型完成了!

推荐者 2
公制: 编辑距离 ,又名 Levenshtein 距离 。
这是一种基于将一个字符串转换成另一个字符串所需的最少操作数来评估两个字符串的不同程度的方法。类似于之前,该功能将默认地接受与推荐器 1 中相同的单词列表。
该函数将反复比较条目与正确单词列表,并获得它们各自的编辑距离。然后,具有最低距离的单词将被视为最佳匹配单词,附加到结果,并由函数返回。
第二款推荐车型完成!
用户输入
现在让我们把我们的模型投入工作。我们将尝试一个由三个单词组成的列表:一个拼错的“请说三个单词”——“threa woeds pleese”,让我们看看效果如何。下面的代码提示用户输入三个单词来创建一个列表 userinput 。
推荐人 1:
结果是“线程”,“悲哀”,“恳求”。

JDreco 输出
推荐者 2:
结果是“tarea”、“Moed”、“please”

editreco 输出
进一步的改进
结果和我预想的相差太远了!与 JDreco 相比,editreco 通过正确建议“请”似乎表现得更好。
这在很大程度上应该是因为算法目前过于“机械”,只根据单个字母判断单词。我相信这表明创建一个谷歌级别的自动更正肯定会花费大量的时间和精力。
我能看到的一些未来的改进将会是通过流行的机器学习使能器 Pytorch 考虑语法和词汇化。
感谢你的阅读!
请在这里找到代码。
通过这篇文章,我希望您已经了解了 nltk 的基础知识,尽管这个库非常庞大,我不可能在一篇文章中涵盖所有内容。我想说,如果付出适当的时间和努力,这将是一个对大多数人来说都很容易理解和编码的数据科学项目。
我通过由 Coursera 主办的密歇根大学 MOOC“Python 中的应用文本挖掘”学到了这一点。推荐!
如果你有问题或者想讨论在后新冠肺炎时代应用数据科学技术的想法,请随时联系我。
我希望我能够以这样或那样的方式帮助您学习数据科学方法!
这是另一篇数据科学文章!
了解岭回归模型背后的理论,如何通过 python 和 scikit-learn 对其进行编码和调优。
medium.com](https://medium.com/python-in-plain-english/ridge-regressions-on-easy-mode-9e7353a0e3f9)
使用 Python 创建漂亮的交互式和弦图
Python 中的数据可视化
一个简单的指南,使用一个简单的函数调用来创建一个令人敬畏的和弦图。

根据数据科学家的说法,当谈到什么是最好的语言时,R vs Python 是一场持续的争论。虽然每种语言都有它的长处,但在我看来,R 有一个难以超越的尖端技巧——R 拥有通过可视化交流结果的神奇工具。
本周,当我试图寻找一种吸引人的方式来可视化数据中各特征之间的相关性时,这一点引起了我的注意。我偶然发现了和弦图!(我们一会儿就会谈到这个)我见过几个使用 Circlize 生成和弦图的 R 示例,在这些示例中,您只需将形状合适的数据传递给 chordDiagram()函数和 ta-da!
你应该看到当我发现和弦图的 Python Plotly 实现时我脸上的表情。即使要得到一个基本的数字,也要付出很多努力。最终结果似乎根本不值得努力。当我在 pypi 上偶然发现和弦时,我几乎放弃了使用和弦图的想法。
好吧,什么是和弦图?
弦图表示一组不同项目之间的流程。这些被称为节点的项目显示在一个圆的周围,流显示为节点之间的连接,显示为弧。
如果这还没有解释清楚,让我们来看一个例子:

作者图片
上面的弦图直观地显示了两个实体(本例中为城市)在旅行者的旅程中同时出现的次数,它允许我们研究它们之间的流动。
如何用最少的努力创造出漂亮的和弦图?
让我带您了解数据准备的过程,然后创建和弦图。
安装:
假设已经安装了 Pandas,您需要从 pypi 安装 chord 包,使用—
pip install chord
数据准备:
我用的是波士顿房价数据集,可以从这里下载。
# importing Pandas libary
import pandas as pd# reading data from csv
df = pd.read_csv("housing.csv")
我的目标是可视化数据集中要素之间的相关性。因此,为了简洁起见,我将删除一些列。我将只剩下 6 个特征。(如果您愿意,可以跳过这一步)
# List of columns to delete and then dropping them.
delete = ['ZN', 'INDUS', 'CHAS', 'DIS','RAD','PTRATIO','B','LSTAT']df.drop(delete, axis=1, inplace=True)
现在让我们使用 Pandas corr()函数创建相关矩阵。
# Now, matrix contains a 6x6 matrix of the values.
matrix = df.corr()# Replacing negative values with 0’s, as features can be negatively correlated.
matrix[matrix < 0] = 0# Multiplying all values by 100 for clarity, since correlation values lie b/w 0 and 1.
matrix = matrix.multiply(100).astype(int)# Converting the DataFrame to a 2D List, as it is the required input format.
matrix = matrix.values.tolist()
这些数据现在非常适合我们的绘图!
绘制图表图:
绘制之前剩下的唯一一步是将实体的名称存储为一个列表。在我的例子中,这些是特性的名称。
# Names of the features.
names = ["Crime Rate","N-Oxide","Number of rooms","Older buildings","Property Tax","Median Price"]
现在,我们要做的就是导入这个包—
from chord import Chord
然后将矩阵和名称传递给 Chord()函数。
Chord(matrix, names).show()#Note: The show() function works only with Jupyter Labs.
# (Not Jupyter notebook)
这将是您的输出:

朱庇特实验室的输出。图片作者。
在我们进一步探索和弦库中可用的其他风格和输出设置之前,让我们看看输出代表什么。
如你所见,当你在犯罪率上徘徊时,你可以看到它与财产税、旧建筑和氮氧化物水平有关,但与中间价格或房间数量无关。现在,您可以将鼠标悬停在连接上,您将看到这些要素之间的相关值。
您可能会注意到,中间价格与其自身 100%相关,所有特性都是如此。这是因为当我们将一个特征与其自身进行比较时,我们得到了一个完美的相关值。如果您愿意,我们可以用一行代码来解决这个问题。
# Operate on the data before converting it into a 2D List# We are just converting all Perfect correlation 100's(Basically the 1’s) to 0 as well.
matrix[matrix == 100] = 0
matrix = matrix.values.tolist()
这是你的输出,一个更清晰的和弦图:

作者图片
将和弦图导出为 HTML:
因为这个包的核心使用了 d3-chord,所以它也给了我们一个选项来输出 ChordDiagram 作为一个完全可编辑的 HTML 文件!多酷啊。
同样,一个简单的方法调用就能帮你做到—
Chord(matrix, names).to_html()# This will create a file 'out.html' in your current directory.
您可以在浏览器中打开 HTML 来查找相同的交互式和弦图,也可以打开。html 并自定义页面的其余部分!
这是我的输出,

以 HTML 的形式输出。图片作者。
我所做的是极其基本的。关键是,HTML 格式的输出为使用和弦图提供了无数的可能性。
造型定制:
颜色:
您可以通过从 d3 分类调色板中传递任何颜色来更改和弦图的颜色。您可以在官方指南中找到输出样本。但这里有几个例子:
# Just add the colors parameter and pass the value.
Chord(matrix, names, colors="d3.schemeDark2").show()

作者图片
# Just add the colors parameter and pass the value.
Chord(matrix, names, colors="d3.schemeAccent").show()

作者图片
# Add all the colors to a list.
coloursList = ["#f50057", "#2196f3", "#00e676", "#ff5722", "#00000", "#ff9100"]# Pass the list to the colors parameter.
Chord(matrix, names, colors=coloursList).show()

作者图片
其他定制:
你也可以自定义标签和不透明度,查看官方指南。
结论:
创建可视化几乎总是数据科学家工作的一部分。部分是这里的关键词,因为这意味着你不能花太多时间来使它们成形,这就是为什么我们寻找提供简单但功能实现的选项。这就是我在本文中试图探索的,用最少的努力创建一个有效的和弦图。
这是我的第一部技术写作作品,我试图将我多年来从这个社区阅读优秀内容时遇到的最佳实践融入其中。我很感激对我工作的任何方面的反馈。
其他资源:
[1] 官方指南 —沙欣·罗斯塔米的博客(图书馆作者)
PyPi 上的[2] 和弦——你可以在这里下载这个包。
创建美观简单的 ML web 应用程序,只需几个步骤就可以大规模部署
本文将教你如何使用 Streamlit 和 AWS CDK 从头开始构建一个 ML 驱动的 web 应用,并从头到尾大规模部署到 AWS Fargate。
你可以看看这个回购的代码。
我们要建造什么?
我们将创建一个 web 应用程序,它可以为我们变魔术。这个技巧就是让某些东西从图像中“消失”。为此,我们将使用一种叫做图像修复的东西,或者说是一种处理过程,在这种过程中,你获取图像中丢失的部分,然后根据背景信息对其进行恢复。我们将研究关于该主题的最新研究论文之一,该论文将于 2020 年 CVPR 上发表,名为“超高分辨率图像修复的上下文残差聚合”。你可以阅读易等人【2020】在 arXiv 中的论文,并在本回购中看到其代码实现。
但在我们实际运行任何图像内画之前,我们需要生成一个遮罩图像,该图像将只在白色前景上显示黑色像素,而我们希望从照片中消失一些东西。您可以手动完成,也可以让计算机为您完成。如果您选择第二个选项,那么您的最佳选择是使用“语义分割”算法,该算法将进行最接近该对象形状的像素级分类。但是,因为我们想尽可能简单,我们将运行“对象检测”,在这些对象的顶部绘制边界框。结果不会那么好,但也足够好了。我们将使用 AWS Rekognition ,因为它使用简单,推理时间短。你总是可以从 GluonCV 网站或者其他一些非常好的框架中了解到关于这两个(以及更多)计算机视觉应用的更多信息。
以下是我们期望得到的结果。您可以在左边看到输入图像(见下面的作者信息),在右边看到输出图像。您可以在demo.ipynb笔记本中找到获得该结果所需的所有步骤。

但是,如果我们想要构建一个更具交互性、动态性、易于调试、非常适合与非技术人员共享模型和结果的东西,该怎么办呢?有一些选项可以帮助你做到这一点,比如 Jupyter Voila 和 Plotly Dash,但它们都不能同时做到所有这些。就在那时,我开始关注 Streamlit ,这是一个开源应用程序框架,它运行在 Python 中,让你用很少的开发工作就能创建看起来很棒的 web 应用程序。我不会详细介绍什么是 Streamlit 以及它是如何工作的,但是您可以在这里看到许多示例和演示,在这里看到一些最佳实践。
入门指南
每个人都有自己处理这类项目的方式,但对我来说最有效的方式是遵循一种精益方法,在这种方法中,我可以快速设计/构建、度量和学习。这些是我通常会做的步骤:
- 创建一个演示笔记本,证明我可以做我希望做的事情,例如,拍摄一个输入图像并生成一个内画图像输出
- 创建一个 Streamlit 应用程序,它将包含与演示笔记本相同的步骤。
- 将所有东西安装到 AWS CDK 项目中,为部署做好准备。
我不会详细介绍第一步,但我会深入探讨如何构建一个 Streamlit 应用程序,以及一旦您知道它可以工作,如何让您的项目适合大规模部署。
要求
1)创建演示笔记本
转到您的终端并克隆这个存储库
$ git clone [https://github.com/nicolasmetallo/legendary-streamlit-demo](https://github.com/nicolasmetallo/legendary-streamlit-demo)
现在,cd进入cdk/app,你会发现demo.ipynb。安装所有依赖项并在笔记本中运行代码。
$ cd cdk/app
$ pip install -r requirements.txt
2)创建您的 Streamlit 应用程序
项目结构
.
├── LICENSE
├── README.md
└── cdk
├── README.md
├── app
│ ├── Dockerfile
│ ├── app.py
│ ├── demo.ipynb
│ ├── helpers.py
│ ├── requirements.txt
│ ├── src
│ │ ├── input_img.png
│ │ ├── local_container.png
│ │ └── magic_trick.png
│ └── test_images
│ ├── image_1.jpg
│ ├── image_2.jpg
│ ├── image_3.jpg
│ ├── image_4.jpg
│ ├── image_5.jpg
│ └── image_6.jpg
├── app.py
├── cdk
│ ├── __init__.py
│ └── cdk_stack.py
├── cdk.json
├── requirements.txt
└── setup.py
您的 Streamlit 应用的主要部分
我们的应用程序将从不同的来源(URL、示例库、用户上传)读取一个输入图像,生成一个内画图像,最后将两者并排绘制在一起。
我们要做的第一件事是导入依赖项和帮助函数。彼得·鲍姆加特纳写了一篇关于重构和编写模块化代码的好文章,应该可以帮助你更好地组织你的代码。
助手函数(作为导入)
from helpers import InPainting
magic_trick = InPainting()
助手功能(在 app.py 中)
def show_images(input_img, output_img):
f = plt.figure(figsize=(20,20))
f.add_subplot(1,2,1)
plt.imshow(input_img)
f.add_subplot(1,2,2)
plt.imshow(output_img)
plt.show(block=True)
st.pyplot(bbox_inches='tight')
阅读您的输入图像
st.header('Read image')
st.image(
'src/input_img.png',
caption='Illustration by [https://blush.design/artists/vijay-verma'](https://blush.design/artists/vijay-verma'),
use_column_width=True,
)
options = st.radio('Please choose any of the following options',
(
'Choose example from library',
'Download image from URL',
'Upload your own image',
)
)input_image = None
if options == 'Choose example from library':
image_files = list(sorted([x for x in Path('test_images').rglob('*.jpg')]))
selected_file = st.selectbox(
'Select an image file from the list', image_files
)
st.write(f'You have selected `{selected_file}`')
input_image = Image.open(selected_file)
elif options == 'Download image from URL':
image_url = st.text_input('Image URL')
try:
r = requests.get(image_url)
input_image = Image.open(io.BytesIO(r.content))
except Exception:
st.error('There was an error downloading the image. Please check the URL again.')
elif options == 'Upload your own image':
uploaded_file = st.file_uploader("Choose file to upload")
if uploaded_file:
input_image = Image.open(io.BytesIO(uploaded_file.read()))
st.success('Image was successfully uploaded')if input_image:
st.image(input_image, use_column_width=True)
st.info('''
Image will be resized to fit within `(1024,1024)`
pixels for easier processing.
''')
else:
st.warning('There is no image loaded.')
在图像上运行您的模型推理
st.header('Run prediction')
st.write('')
prediction_checkbox = st.checkbox('Do a magic trick!')
if input_image and prediction_checkbox:
try:
with st.spinner():
output_image = magic_trick.run_main(input_image)
show_images(input_image, output_image)
except Exception as e:
st.error(e)
st.error('There was an error processing the input image')
帮助者. py
为了生成内画图像,我们需要输入图像和遮罩图像,其中除了我们的目标以外,每个像素都是白色的。如前所述,我们将使用 AWS Rekognition 来检测一个对象和一个自定义类,以根据该检测创建一个遮罩图像。
class Rekognition:
def __init__(self):
self.client = boto3.client(
'rekognition',
region_name = 'eu-west-2', # not needed
)def predict_labels(self, image_bytes, max_labels=10, min_conf=90):
response = self.client.detect_labels(
Image = {'Bytes': image_bytes},
MaxLabels = max_labels,
MinConfidence = min_conf,
)
return response['Labels']
def return_mask_img(self, image_bytes):
image = Image.open(io.BytesIO(image_bytes))
imgWidth, imgHeight = image.size
blank = Image.new('RGB', image.size, (255, 255, 255))
draw = ImageDraw.Draw(blank)
response = self.predict_labels(image_bytes)
for idx, label in enumerate(response):
name = label['Name']
instances = label['Instances']if len(instances) == 0: continue
for instance in instances:
confidence = instance['Confidence']
box = instance['BoundingBox']
left = imgWidth * box['Left']
top = imgHeight * box['Top']
width = imgWidth * box['Width']
height = imgHeight * box['Height']points = (
(left, top),
(left + width, top),
(left + width, top + height),
(left , top + height),
(left, top),
)# draw bounding box
draw.rectangle([left, top, left + width, top + height], fill='black')
return blank
一旦我们有了这两个图像,我们应该能够运行图像在绘画模型预测。
class InPainting:
def __init__(self):
self.rekognition = Rekognition()
self.multiple = 6
self.INPUT_SIZE = 512 # input image size for Generator
self.ATTENTION_SIZE = 32 # size of contextual attention
def PIL_to_cv2(self, pil_img):
np_img = np.array(pil_img.convert('RGB'))
return cv2.cvtColor(np_img, cv2.COLOR_RGB2BGR)
def PIL_to_image_bytes(self, img):
buffer = io.BytesIO()
img.save(buffer, format='JPEG')
return buffer.getvalue()
def cv2_to_PIL(self, cv2_im):
cv2_im = cv2.cvtColor(cv2_im, cv2.COLOR_BGR2RGB)
return Image.fromarray(cv2_im)
def run_main(self, input_image, max_size = (1024,1024)):
with tf.Graph().as_default():
with open('sample-imageinpainting-HiFill/GPU_CPU/pb/hifill.pb', "rb") as f:
output_graph_def = tf.GraphDef()
output_graph_def.ParseFromString(f.read())
tf.import_graph_def(output_graph_def, name="")with tf.Session() as sess:
init = tf.global_variables_initializer()
sess.run(init)
image_ph = sess.graph.get_tensor_by_name('img:0')
mask_ph = sess.graph.get_tensor_by_name('mask:0')
inpainted_512_node = sess.graph.get_tensor_by_name('inpainted:0')
attention_node = sess.graph.get_tensor_by_name('attention:0')
mask_512_node = sess.graph.get_tensor_by_name('mask_processed:0')
input_image.thumbnail(max_size)
image_bytes = self.PIL_to_image_bytes(input_image)
raw_mask = self.PIL_to_cv2(self.rekognition.return_mask_img(image_bytes))
raw_img = self.PIL_to_cv2(input_image)
inpainted = self.inpaint(
raw_img, raw_mask, sess, inpainted_512_node,
attention_node, mask_512_node, image_ph, mask_ph, self.multiple)
return self.cv2_to_PIL(inpainted)
创建 Dockerfile 文件
FROM python:3.7
EXPOSE 8501
WORKDIR /app
COPY requirements.txt ./requirements.txt
RUN pip3 install -r requirements.txt
RUN git clone [https://github.com/Atlas200dk/sample-imageinpainting-HiFill.git](https://github.com/Atlas200dk/sample-imageinpainting-HiFill.git) && \
cd sample-imageinpainting-HiFill && \
git checkout 1f7f769bd1ea225d4d5c8b094dd261ca9172927b
COPY . .
CMD streamlit run app.py \
--server.headless true \
--browser.serverAddress="0.0.0.0" \
--server.enableCORS false \
--browser.gatherUsageStats false
构建映像并在本地运行以进行调试
在您的终端中运行下面的命令来构建您的容器映像
$ docker build -t demo/magic-trick .
现在运行容器
$ docker run -it — rm -p ‘8501:8501’ demo/magic-trick
如果你打开浏览器,进入 http://localhost:8501 ,你应该能看到下面的… 成功!😃

3)使用 AWS CDK 将您的 Streamlit 应用程序部署到 AWS Fargate
快速介绍
AWS CDK 是一个软件开发框架,用于在代码中定义云基础设施,并通过 AWS CloudFormation 进行配置,使您能够:
- 可预测地重复创建和配置 AWS 基础设施部署。
- 利用 AWS 产品,如 Amazon EC2、Amazon Elastic Block Store、Amazon SNS、Elastic Load Balancing 和 Auto Scaling。
- 在云中构建高度可靠、高度可伸缩、经济高效的应用程序,而无需担心创建和配置底层 AWS 基础架构。
- 使用模板文件将资源集合作为一个单元(堆栈)一起创建和删除。
AWS Fargate 是亚马逊 ECS 和 EKS 的计算引擎,允许你运行容器,而不必管理服务器或集群。我们将使用这两种服务来轻松地大规模部署我们的容器。
如果你不理解所有这些,不要太担心,因为有一个很好的入门指南供你参考,还有官方 Python 参考文档供你查阅。我将按照官方的 ECS 示例列出您需要完成的每个步骤,但是因为这些步骤中的大部分已经在此 repo 中完成(例如,创建项目目录),所以在跳到下面的部署您的堆栈之前,请随意初始化 AWS CDK 并安装所有依赖项。
配置您的 AWS 凭据
如果您打算从本地机器部署您的栈,您应该确保您的 AWS 凭证在您的环境中被正确设置。你可以在文档中了解更多信息。
打开您的终端并运行以下命令。当询问时,添加您的访问密钥和密钥。
$ aws configure
另一方面,如果您打算从 AWS 实例(例如 EC2、SageMaker 等)部署您的堆栈。)然后,您的环境将采用您分配给该实例的凭证和角色,您不需要进行任何配置。你只需要仔细检查你的角色能不能做你想做的一切。
安装自动气象站 CDK
转到您的终端,使用以下命令安装 AWS CDK。
$ npm install -g aws-cdk
(可选)如果您需要更新 AWS CDK 版本,请运行
$ npm update -g aws-cdk
运行以下命令验证安装是否正确,并打印 AWS CDK 的版本号。
$ cdk — version
更新您的语言依赖
如果您收到一条错误消息,提示您的语言框架已过期,请使用以下命令之一来更新 AWS CDK 支持该语言所需的组件。
$ pip install — upgrade aws-cdk.core
创建您的项目目录并初始化 AWS CDK
让我们首先创建一个保存 AWS CDK 代码的目录,然后在该目录中创建一个 AWS CDK 应用程序。
$ mkdir cdk
$ cd cdk
$ cdk init — language python
$ source .env/bin/activate
$ pip install -r requirements.txt
您生成的cdk/cdk_stack.py应该是这样的。
from aws_cdk import coreclass CdkStack(core.Stack):def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
super().__init__(scope, id, **kwargs)# The code that defines your stack goes here
构建并运行应用程序,并确认它创建了一个空堆栈。
$ cdk synth
您应该看到如下所示的堆栈,其中CDK-VERSION是CDK的版本,NODE-VERSION是 Node.js 的版本。)
Resources:
CDKMetadata:
Type: AWS::CDK::Metadata
Properties:
Modules: aws-cdk=CDK-VERSION,[@aws](http://twitter.com/aws)-cdk/core=CDK-VERSION,[@aws](http://twitter.com/aws)-cdk/cx-api=CDK-VERSION,jsii-runtime=node.js/NODE-VERSION
添加 Amazon EC2 和 Amazon ECS 包
为 Amazon EC2 和 Amazon ECS 安装 AWS 构造库模块。
$ pip install aws_cdk.aws_ec2 aws_cdk.aws_ecs aws_cdk.aws_ecs_patterns
创建一个 Fargate 服务
使用 Amazon ECS 运行容器任务有两种不同的方式:
- 使用
Fargate启动类型,Amazon ECS 为您管理运行容器的物理机器。 - 使用
EC2启动类型,在这里进行管理,比如指定自动缩放。
对于本例,我们将创建一个运行在 ECS 集群上的 Fargate 服务,它由一个面向互联网的应用程序负载平衡器提供支持。在此基础上,我们将向该集群添加自动伸缩功能,并将策略附加到任务角色,以便容器能够使用 AWS Rekognition。
将以下 AWS 构造库模块导入添加到指定的文件中。
文件:cdk/cdk_stack.py
from aws_cdk import (
aws_ec2 as ec2,
aws_ecs as ecs,
aws_ecr as ecr,
aws_iam as iam,
aws_ecs_patterns as ecs_patterns,
core,
)
用下面的代码替换构造函数末尾的注释。
# Create a VPC
vpc = ec2.Vpc(
self, "WebDemoVPC",
max_azs = 2,
) # default is all AZs in region,
# but you can limit to avoid reaching resource quota# Create ECS cluster
cluster = ecs.Cluster(self, "WebDemoCluster", vpc=vpc)# Add an AutoScalingGroup with spot instances to the existing cluster
cluster.add_capacity("AsgSpot",
max_capacity=2,
min_capacity=1,
desired_capacity=2,
instance_type=ec2.InstanceType("c5.xlarge"),
spot_price="0.0735",
# Enable the Automated Spot Draining support for Amazon ECS
spot_instance_draining=True
)# Build Dockerfile from local folder and push to ECR
image = ecs.ContainerImage.from_asset('app')# Create Fargate service
fargate_service = ecs_patterns.ApplicationLoadBalancedFargateService(
self, "WebDemoService",
cluster=cluster, # Required
cpu=512, # Default is 256 (512 is 0.5 vCPU)
desired_count=1, # Default is 1
task_image_options=ecs_patterns.ApplicationLoadBalancedTaskImageOptions(
image=image,
container_port=8501,
),
memory_limit_mib=2048, # Default is 512
public_load_balancer=True) # Default is True# Add policies to task role
fargate_service.task_definition.add_to_task_role_policy(iam.PolicyStatement(
effect=iam.Effect.ALLOW,
actions = ["rekognition:*"],
resources = ["*"],
)
)# Setup task auto-scaling
scaling = fargate_service.service.auto_scale_task_count(
max_capacity=10
)
scaling.scale_on_cpu_utilization(
"CpuScaling",
target_utilization_percent=50,
scale_in_cooldown=core.Duration.seconds(60),
scale_out_cooldown=core.Duration.seconds(60),
)
设置 AWS CDK Python 脚本时需要考虑的一些事项
- CloudFormation 尚不支持 Fargate Spot 实例(截至 2020 年 5 月 31 日)
- 任务执行角色不同于任务角色。基本上,执行角色是执行 ECS 操作(如推和拉映像)的角色,任务角色是任务本身调用其他 AWS 服务(如 Rekognition、S3 等)所使用的角色。在 StackOverflow 问题中了解更多信息。
- 我们已经建立了一个 ECS 集群,它具有一个包含 spot 实例的自动扩展组,并且当 cpu 利用率增加到 50%以上时,可以启动多达 10 个新任务。你可以在这里阅读更多关于任务自动缩放的内容。
- 不要在每次想要部署项目时构建容器映像并将其推送到 ECR,您还可以从 ECR 存储库中提取一个现有的映像。你可以用
repository = ecr.Repository.from_repository_arn(
self, "{repository-name}",
"arn:aws:ecr:{region-name}:{account-id}:repository/{repository-name}")
image = ecs.ContainerImage.from_ecr_repository(repository=repository, tag="latest")
部署您的堆栈
当您的应用程序只有一个堆栈时,不需要指定堆栈名称,您可以运行
$ cdk deploy
如果您得到一个错误,如
This stack uses assets, so the toolkit stack must be deployed to the environment (Run “cdk bootstrap aws://unknown-account/unknown-region”)
然后,在运行cdk deploy之前,您需要引导您的默认概要文件所使用的帐户。
$ cdk bootstrap
…
✅ Environment aws://{your-account-id}/{your-region-name} bootstrapped.
整个过程大约需要 10 到 20 分钟,因为我们也在将我们的容器映像推送到 ECR。一旦该过程成功结束,您应该会看到类似这样的内容:
✅ cdkOutputs:
cdk.WebDemoServiceLoadBalancerDNS******A5 = cdk-WebDemo-PV******KA7D-******197.eu-west-2.elb.amazonaws.com
cdk.WebDemoServiceServiceURL******7B = [http://cdk-WebDemo-PV******KA7D-******197.eu-west-2.elb.amazonaws.com](http://cdk-WebDemo-PV******KA7D-******197.eu-west-2.elb.amazonaws.com)Stack ARN:
arn:aws:cloudformation:eu-west-2:************:stack/cdk/c7f457f0-a34d-11ea-a167-******e602c
现在,当你打开浏览器,进入cdk.WebDemoServiceServiceURL,你会看到你的应用程序。请注意,由于我们只为该任务分配了 0.5 个 vCPU,所以推断时间会很长,在 20 到 30 秒之间。但是您可以随时返回,更改这一点,并使用cdk deploy重新部署。

恭喜你!您的应用程序现已上线😃
删除您的 AWS CDK 项目
如果你不再希望你的应用程序存在,你可能需要清除 AWS CDK 设置的所有东西,以避免招致任何意想不到的成本。
$ cdk destroy
参考
- 易,张,唐,张,徐,(2020)。超高分辨率图像修复的上下文残差聚合。arXiv 预印本 arXiv:2005.09704
图片包含在 **test_images** 文件夹中
image_1.jpg,蒂姆·多弗勒,链接image_2.jpg、巴特尔米·德·马泽诺德、链接image_3.jpg、唐纳德·詹纳蒂、链接image_4.jpg、韩亚库米、链接image_5.jpg、纪尧姆·德·热尔曼、链接image_6.jpg、帖木儿【罗马诺夫】、链接
用 Python 创建漂亮的架构图
实践教程
停止花费时间手动调整未对准的箭头

建立与代码从要点链接这里。
一些背景故事
本周早些时候,我偶然发现了一个 Python 库,它有一个非常吸引人的价值主张。这个库叫做图,正如它的名字一样,它创建图。这些生成的图表通常是我通过笨拙地将图像粘贴到 draw.io 或 Google 图表中而创建的,之后我会浪费几个小时来正确地对齐一切。除了那个令人疲惫的过程之外,当我后来需要更新这些图时,仅仅为了对架构的一些改变,就需要提升和移动超过一半的组件。在进一步研究了 library 之后,我发现它能够减轻我的痛苦。
开始使用您自己的图表
开始构建这些图的第一个要求是安装 Python 3.6 或更高版本。一旦是这种情况,你将需要安装 GraphViz,因为这是什么呈现的图表。Github 库实际上也有一个相当不错的“入门”部分,所以如果你需要帮助安装任何东西,请随意参考这里的。一旦用您最喜欢的 Python 包管理器安装了库“图表”,您就可以开始创建了。
对我来说,开始就像下面的命令一样简单,因为我满足了最初的要求。
组件类型
图形库为许多不同的提供者提供组件。以下可能是 14 个可用用例中最相关的。
- AWS/GCP/Azure —这些提供商公开了正式的云服务资产,您将在任何利用主要云提供商之一的图表中使用这些资产。我的团队主要在 GCP 工作,在偶然发现这个库之前,我会花几个小时手工构建这些图,所以当我发现这些节点资产唾手可得时,我有点兴奋。
- 通用和本地 —如果您希望以云不可知的方式说明底层技术,这些节点可能会一起使用。例如,通过显示 Google 数据流为一个架构提供一个 Beam 组件。
- 框架 —如果你想用编程语言说明一个节点,这些组件会很有用。
- SaaS——甚至有一个 SaaS 节点的集合,当你想显示你的架构有通知在 Slack 之类的地方着陆时,它会派上用场。
图表概念
图表 —图表是表示图表的主要对象。
节点——代表单个系统组件的抽象概念。
集群 —允许您将节点组织成组(或集群),而不是孤立的组件。
边 —表示节点之间的链接。
你的第一张图
现在你已经知道了基本概念,让我们按照我们学习这些概念的顺序,用代码构建一个极其简单的图表。我们将构建的示例图将是一个简单的 AWS 负载平衡网站,它使用 PostgreSQL 数据库和 Redis 缓存,因此我们可以使用多个组件提供者。
步骤 1:创建图表工作空间
这将简单地呈现一个带有指定标签的空白图,如下所示。

用 gist 链接的代码在这里构建。
步骤 2:添加节点
现在我们有了工作空间,是时候添加我们网站需要的节点了。我们要添加的节点来自两个不同的提供者。AWS 和 OnPrem 提供程序。如果你真的这样做,你可能会坚持使用 AWS,因为他们有 RDS 和 ElastiCache 等产品,你可能会与云提供商一起使用。
如您所见,我们不再有空白图表。我们的每一个节点都被描绘出来,这些是我们想要构建的架构的“成分”。接下来的步骤是将我们的一些节点组织成逻辑分组,然后用边连接每个节点。

用链接到这里的要点中的代码构建。
步骤 3:对节点进行分组(可选)
在本例中,我们将只对负载平衡的 web 服务器进行分组。在我过去创建的许多图表中,这并不总是必要的,但是随着您的体系结构的增长,将这些节点分组到集群中通常会增强可读性。
下面您可以看到,要做到这一点,我们只需要将节点的实例化移动到我们正在创建的集群的范围内。
如您所见,该图仍然只是一个节点列表,但是我们现在已经将适当的节点聚集到逻辑分组中。

用链接到这里的要点中的代码构建。
第四步:将所有内容联系在一起
在最后一步中,我们将不会链接我们刚刚安排在我们的体系结构中使用的节点。当我需要更新或者调整一个架构的时候,这个任务花费了我最长的时间。如果你看一下下面,它只是一个用双箭头定义流向每个节点的问题,你就完成了!在这个例子中,我们将只链接没有标签的节点,但是如果你看一下文档,将标签应用到你的链接是一个非常简单的任务。
生成的图像如下所示,您现在可以看到图中每个节点之间的逻辑流。通过更改定义节点的顺序,可以反转此流程。除了调整流程,你还可以改变很多东西,因为一个边缘对象包含三个属性:标签、颜色和样式。我们将不会涵盖如何在这里柚木这些。如果您有兴趣了解更多信息,本文末尾提供了文档链接,这些属性反映了相应的 graphviz edge 属性,如果您过去使用过该工具,这将使事情变得更容易。

用链接到这里的要点中的代码构建。
结论
现在你已经开始用代码构建一个漂亮的图表,当涉及到自动化的可能性时,利用这个工作流有很大的潜力,并且节省了架构图的一般维护的时间。
使用这个工具节省的时间会让我在将来使用这个方法。我当然不会错过手动调整图表、小心地将组件和箭头与我的架构的每一次迭代对齐所付出的努力。
我希望我钻研用代码构建图的经历是有趣的,并且对您未来的绘图工作可能有用。感谢阅读!
资源
用 Python 创建漂亮的交互式可视化
Plotly 和 Dash 入门

Plotly 是一个交互式的 Python 库,它提供了一个简单的界面,可以实现多种可视化。
Python 中有许多不同的可视化库。与 Matplotlib 相比,Plotly 与众不同的是其情节的交互性、可视化的丰富性和多样性、相对简单性,以及使用 Dash 模块将可视化部署为 web 应用的能力。
Plotly 工具套件有许多不同的部分,当我第一次开始使用它们时,我发现导航有点困难。在本文中,我想简单介绍一下 Plotly 的核心元素,包括标准绘图模块 Plotly express 和 Dash。除了一些简单的代码之外,还有让您快速使用这些工具的示例。
1.标准绘图
Plotly 可以 pip 安装。
pip install plotly
Plotly 可视化渲染为 HTML 文件。如果您在 Jupyter 笔记本上工作,并且想要直接渲染图像,您需要安装 ipywidgets 包。
pip install "notebook>=5.3" "ipywidgets>=7.2"
或者你用的是 JupyterLab。
pip install jupyterlab "ipywidgets>=7.5"
jupyter labextension install jupyterlab-plotly@4.9.0
Plotly 使用称为图形的数据结构,图形可以表示为字典,在这种情况下,您可以使用plotly.io模块。或者作为通过plotly.graph_objects模块呈现的图形对象。
图形对象通常被认为是比字典更好的选择,因为它们允许精确的数据验证,支持用于更新已经构建的图形的更高级的便利功能,并且图形对象的语法使得代码更紧凑。
让我们导入一个玩具数据集,并探索标准绘图的基本功能。下面的代码导入了波士顿房价数据集,这是一个流行的玩具数据集,用于 scikit-learn 库中的回归分析。
数据的前几行如下所示。

让我们使用图形对象模块来探索房价和房间数量之间的关系。你会注意到我正在使用我上面提到的助手功能来给可视化添加标题。

2.Plotly express
如果你需要创建一个定制的可视化,标准绘图模块是有用的。然而,如果你想创建一些非常标准的东西,比如上面显示的散点图,那么plotly.express API 是最好的选择。
这个模块允许你在一行代码中为最常见的可视化创建完整的图形。它还能让你轻松控制颜色、风格和标签。
使用这个模块,我们只用一行代码就可以创建上面的散点图。颜色、标签和样式控制均可通过px.scatter功能获得,轴标签会自动添加。
由plotly.express提供的‘开箱即用’图表有大量不同的选项和控件,您可以在这里探索所有选项。
例如,下面的代码创建了一个直方图来显示 CHAS 变量的分布。我使用了histnorm选项来应用标准化以更好地可视化分布,使用hover_data选项来控制悬停时的交互。

3.破折号
Dash 也是 Plotly 工具套件的一部分,是一个用于开发数据分析仪表板的框架,所有 Plotly 可视化都可以轻松嵌入到应用程序中。
仪表板需要单独安装。
pip install dash
可以在 Jupyterlab 中显示 Dash 应用程序,但是您需要安装这个 JupyterDash 扩展。
pip install "jupyterlab>=1.0" jupyterlab-dash==0.1.0a3
jupyter labextension install jupyterlab-dash@0.1.0-alpha.3
或者,Dash 将在 localhost 上托管应用程序,当您运行代码时,该地址将显示在输出中。

无论何时fig.show被用于显示可视化,使用 Plotly express 或标准绘图,你都可以将相同的绘图传递给 Dash。
Dash 应用程序的布局由app.layout决定,它使用dash_core_components和dash_html_components的组合向仪表板添加图表、表格、交互性和文本。
下面显示的代码使用我们用plotly.express创建的图表创建了一个基本的 Dash 应用程序。生成的仪表板如下所示。

Dash 应用程序最有用的一个方面是,您可以通过使用[callbacks](https://dash.plotly.com/basic-callbacks)使您的仪表板具有交互性。核心组件模块包含各种不同的交互式组件,包括下拉菜单、滑块和文本框。
下面的代码向仪表板添加了一个下拉菜单,允许您过滤 RAD 特性以查看每个唯一值的分布。生成的仪表板显示在代码下方。

我最近发现自己开始使用 Plotly 作为我的首选可视化库,因为我发现你可以如此轻松地实现的分析质量是目前任何其他 Python 绘图库都无法比拟的。自从 Pandas 将 Plotly 添加为其绘图功能的可用后端后,情况就变得更加如此。
我以前写过这篇文章,概述了如何使用 Plotly 作为熊猫可视化的后端。如果您想将一些非常快速分析片段放在一起,这是非常有用的。
创建丰富的可视化和仪表板与熊猫绘图后端为 Plotly 和 Bokeh
towardsdatascience.com](/plotting-in-pandas-just-got-prettier-289d0e0fe5c0)
感谢阅读!
我每月都会发一份简讯,如果你想加入,请点击此链接注册。期待成为您学习旅程的一部分!
如何使用 Plotly、Python 创建二项式分布图

有时,Python 图表是您的论点或您试图构建的数据案例的必要元素。本教程是关于创建二项式或正态分布图。我们将从声明一个二项式分布的数字数组开始。我们只需从 scipy.stats 导入 binom 就可以做到这一点。
from scipy.stats import binom
n = 1024
size = 1000
prob = 0.1
y = binom.rvs(n, prob, size=size)
这段代码生成 1000 个数字,共 1024 次,成功概率为 0.1。一旦完成了这个,接下来我们要计算数组中数字的频率。我们可以通过将此作为数据帧并使用以下逻辑创建频率仓来实现这一点。
import numpy as np
import pandas as pd# Creating X array for numbers between the maximum and minimum values of y and making it a dataframe
x = np.arange(y.min(), y.max())
xx = pd.DataFrame(x)# Making y a dataframe and generating an empty array yy
d = pd.DataFrame(y, columns = ['Data'])
yy = []# Calculating frequency of all numbers between maxiumum and minimum values
for k in range(len(x)):
yy.append(d[d['Data'] == x[k]].count()[0])# Making frequency data frame and concatenating it with the xx
freq = pd.DataFrame(yy, columns=['Frequency'])
data = pd.concat([xx, freq], axis=1)
data.columns = ['Score', 'Frequency']
现在我们有了分数和频率箱。我们可以使用 plotly.graph 使用这些数据生成一个二项式图。
import plotly.graph_objects as go
fig = go.Figure( # Loading the data into the figur
data=[go.Scatter(x=data['Score'], y=data['Frequency'],
mode="lines",
line=dict(width=2, color="blue"))], # Setting the layout of the graph
layout=go.Layout(
xaxis=dict(range=[y.min(), y.max()], autorange=False),
yaxis=dict(range=[data['Frequency'].min(), data['Frequency'].max()], autorange=False),
title="Binomial Curve",
updatemenus=[dict(
type="buttons",
buttons=[dict(label="Play",
method="animate",
args=[None])])]
))
fig.show()
下图是使用上面的代码生成的。

正如我们所看到的,曲线展示了一个基本的二项式行为,有很多噪声,随机徘徊在预期路径的上方和下方。但是通过重复这个过程很多次并平均结果,它可以很容易地变成一个完整的二项式图。在我的例子中,我执行了 1500 次上述步骤。请查看下面的代码:
n = 1024
size = 1000
prob = p / 10
x = np.arange(70, 135)
yy = []
tt = []# Repeating the step 1500 times, rest code is same as above
for a in range(1500): y = binom.rvs(n, prob, size=size)
d = pd.DataFrame(y, columns = ['Data'])
for k in range(len(x)):
yy.append(d[d['Data'] == x[k]].count()[0])
tt.append(yy)
yy = []
y = []kk = pd.DataFrame(tt).T
y = kk.mean(axis=1)
N = len(y)
上面的代码生成了一个新的数组“y ”,它对数据中所有分数的频率进行了平均。我们可以使用下面的代码生成一个新的数据框并查看数据:
data = pd.DataFrame([x,y]).T
data.columns = ['Score', 'Frequency']
data.head()
使用 plotly 代码再次绘制这些数据,我们得到了一个好看的二项式图。

有了上面的图表,我们可以对数据做更多的处理,比如我们可以用 plotly 来制作图表的梯度或它在每一点的导数的动画。
任何一点的导数都可以用下面的公式进行数值计算。

我们可以使用 pandas 实现这个公式,计算所有相关点的梯度值。
# Declaring an empty array
deri = []# Setting first derivative to zero
fir = 0
deri.append(fir)# Calculating the derivative all points other than first and last points
for a in range(1,64):
diff = (data['Frequency'][a+1] - data['Frequency'][a-1])/2
deri.append(diff)# Setting last derivative to zero
end = 0
deri.append(end)der = pd.DataFrame(deri, columns = ['Derivatives'])
data = pd.concat([data, der], axis = 1)
请注意,我们特意将零作为数据中第一个和最后一个点的值。这样做是因为导数公式需要前值和后值。第一个值缺少前一个值,最后一个值缺少后一个值。此后,为了方便起见,两者都保持为零。
现在我们有了导数,我们需要计算我们需要在 plotly 上制作动画的渐变线的开始和结束坐标。
sx = []
sy = []
ex = []
ey = []
Gap = 3.5for b in range(0,65):
#Computing Start Coordinates
ssx =data['Score'][b] - Gap
sx.append(ssx)
ssy = data['Frequency'][b] - Gap * data['Derivatives'][b]
sy.append(ssy)
#Computing End Coordinates
eex = data['Score'][b] + Gap
ex.append(eex)
eey = data['Frequency'][b] + Gap * data['Derivatives'][b]
ey.append(eey)cord = pd.DataFrame([sx, sy, ex, ey]).T
cord.columns = ['XStart', 'YStart', 'XEnd', 'YEnd']
现在我们已经完成了,我们可以可视化产生的动画。

此外,如果我们想要在该图上标记区域并添加文本,我们可以使用下面的代码片段轻松完成。
fig.add_trace(go.Scatter(x=[70,85,85,70], y=[0,0,50,50], fill='toself', mode='lines', line_color='#FF5A5F', opacity = 0.3))
fig.add_trace(go.Scatter(x=[85,102,102,85], y=[0,0,50,50], fill='toself', mode='lines', line_color='#C81D25', opacity = 0.3))
fig.add_trace(go.Scatter(x=[102,119,119,102], y=[0,0,50,50], fill='toself', mode='lines', line_color='#0B3954', opacity = 0.3))
fig.add_trace(go.Scatter(x=[119,135,135,119], y=[0,0,50,50], fill='toself', mode='lines', line_color='#087E8B', opacity = 0.3))fig.add_trace(go.Scatter(
x=[77.5, 93.5, 110.5, 127],
y=[40, 40, 40, 40],
mode="text",
name="Regions",
text=["Low Risk", "High Risk", "Stabilization", "Recovery"],
textposition="top center",
textfont=dict(
family="sans serif",
size=20,
color="black"
)
))fig.show()
我们最终得到下图。

如果你仍然对我在做什么感到好奇,请看看我的下一个博客,在这里,所有这些技术都被用来可视化“新冠肺炎的全球地位”。敬请期待,干杯。
二项式曲线的完整 Jupyter 笔记本实现可以在这里找到。
通过使用 Python 抓取 Google Play 应用评论来创建用于情感分析的数据集
了解如何收集 Android 应用的评论,并使用这些信息建立一个用于情感分析的数据集

马库斯·温克勒的照片
TL;DR 了解如何通过收集 Android 应用程序的用户评论来创建用于情感分析的数据集。您需要将应用程序和检查信息转换为数据框,并将其保存为 CSV 文件。
“成功创造人工智能将是人类历史上最大的事件。不幸的是,这也可能是最后一次,除非…
leanpub.com](https://leanpub.com/getting-things-done-with-pytorch)
您将学习如何:
- 为数据集设置目标和包含标准
- 通过抓取 Google Play 获得真实世界的用户评论
- 使用 Pandas 将数据集转换并保存为 CSV 文件
设置
让我们安装所需的包并设置导入:
数据集的目标
你希望你的应用得到反馈。消极和积极都是好的。但是消极的一面可能会暴露出您的服务所缺少的关键特性或停机时间(当它更加频繁时)。
幸运的是,Google Play 有大量的应用程序、评论和分数。我们可以使用 google-play-scraper 包收集应用信息和评论。
你可以选择大量的应用程序进行分析。但是不同的应用类别包含不同的受众、特定领域的怪癖等等。我们从简单的开始。
我们想要已经存在一段时间的应用程序,因此可以有机地收集意见。我们希望尽可能减少广告策略。应用程序不断更新,因此审查的时间是一个重要因素。
理想情况下,您会希望收集所有可能的评论并加以利用。然而,在现实世界中,数据通常是有限的(太大、不可访问等)。所以,我们会尽力而为。
让我们从生产力类别中选择一些符合标准的应用。我们将使用 AppAnnie 选择一些美国顶级应用:
抓取应用程序信息
让我们收集每个应用程序的信息:
我们得到了所有 15 个应用程序的信息。让我们编写一个助手函数,它可以更好地打印 JSON 对象:
以下是列表中的应用程序信息示例:
这包含了许多信息,包括评级数量,评论数量和每个分数的评级数量(1 到 5)。让我们忽略所有这些,看看它们美丽的图标:

我们数据集中的应用图标
我们将通过将 JSON 对象转换成 Pandas 数据帧并将结果保存到 CSV 文件中来存储应用程序信息,以备后用:
抓取应用评论
在一个理想的世界里,我们会得到所有的评论。但是有很多,我们正在搜集数据。那不太礼貌。我们做什么呢
我们想要:
- 平衡数据集—每个分数的评论数量大致相同(1-5)
- 每个应用的代表性评论样本
我们可以通过使用刮包选项过滤复习分数来满足第一个要求。对于第二个问题,我们将根据评论的有用性对其进行排序,这是 Google Play 认为最重要的评论。为了以防万一,我们还会从最新的数据中获取一个子集:
请注意,我们将应用 id 和排序顺序添加到每个评论中。这里有一个例子:
repliedAt和replyContent包含开发人员对评审的回应。当然,他们可能会失踪。
我们获得了多少应用评论?
15750
让我们将评论保存到 CSV 文件中:
摘要
干得好!您现在拥有一个数据集,其中包含来自 15 个生产力应用程序的超过 15k 条用户评论。当然,你可以疯狂地得到更多。
“成功创造人工智能将是人类历史上最大的事件。不幸的是,这也可能是最后一次,除非…
leanpub.com](https://leanpub.com/getting-things-done-with-pytorch)
您学习了如何:
- 为数据集设定目标和期望值
- 抓取 Google Play 应用程序信息
- 收集 Google Play 应用的用户评论
- 将数据集保存到 CSV 文件
接下来,我们将使用这些评论对 BERT 进行情感分析。但是首先,我们必须做一些文本预处理!
参考
最初发表于https://www.curiousily.com。
使用 Python 的桌面通知应用程序只需 5 分钟
在本文中,您将学习使用 python 通过几个简单的步骤为您的 PC 创建一个定制的桌面通知程序。

照片由 Cookie 在 Unsplash 上的 Pom 拍摄
介绍
你有没有尝试过根据自己的需求创建一个桌面通知应用程序?您知道使用 python 只需几个简单的步骤就可以做到这一点吗?
不要担心,让我们从头开始,在本文中,我们将创建一个桌面通知应用程序,用于获取可怕的冠状病毒的每日统计数据。
你从这篇文章中学到了什么
- 安装所需的 python 包。
- 从网上读取冠状病毒数据。
- 创建桌面通知应用程序。
- 让你的程序在后台运行。
我们开始吧
安装需要的 python 包
我们需要为这个应用程序下载两个重要的包。
注意:如果您使用 Windows,您需要在命令提示符下键入这两个命令;如果您使用 Linux,您需要在终端上键入这两个命令
- 请求(从 web 获取数据)
**pip install requests**
2.plyer(用于在您的电脑上创建通知)
**pip install plyer**
从网络上读取冠状病毒数据
我们可以使用下面提供的 URL 获取冠状病毒数据,您可以自由地将国家名称替换为您自己的国家名称,对于此应用程序,我们将使用印度的冠状病毒数据。
**https://corona-rest-api.herokuapp.com/Api/india**
网站看起来像这样

图片由 Satya Ganesh 提供
创建桌面通知程序
到目前为止,我们已经获得了构建这个应用程序所需的所有工具,所以现在让我们编写这个应用程序的代码
注意:如果你在离线编译器中编写这个代码,会比在线编译器更容易,因为在本文的后面,我们会让这个应用程序在你的 PC 上作为后台进程运行,如果你在在线编译器中运行,那么你需要下载文件,而在离线编译器中这是不必要的。我会建议用 Visual Studio。
part1(导入库)
第二部分(从 web 上检索数据)
part3(创建自定义通知)
就这样,我们准备运行我们的应用程序,在实际运行我们的应用程序之前,您需要了解一些您可以进行的更改,以便根据您的需求定制您的应用程序。
超时—告知通知应该在桌面上显示多长时间
time.sleep ()—告知通知应在多长时间间隔后弹出
下面是您在运行应用程序后看到的通知。

图片由 Satya Ganesh 提供
让你的应用在后台运行
因此,您最终创建了一个 python 应用程序,当您运行它时,它运行良好。但是你不觉得这是一项繁琐的工作吗,每次运行你的应用程序都要得到一个通知?
这里有一个解决方案,你可以通过在你的电脑上运行你的应用程序作为后台进程来实现自动化。
如何让一个 python 应用在后台运行?
只需按照这个简单的命令让您的应用程序在后台运行,注意,如果您使用的是 Windows,您需要在命令提示符下键入这个命令;如果您使用的是 Linux,您需要在终端上键入这个命令。
注意: 用你的文件名替换<你的文件名
*pythonw.exe .\<your-file-name-here>example pythonw.exe .\desktopNotifier.py*
就这样,您的应用程序现在开始在后台运行
你如何确认你的应用在后台运行?
在你的电脑中打开任务管理器,你可以看到在后台进程中你可以看到 python 正在运行

图片由 Satya Ganesh 提供
如何停止接收通知?
很简单,在任务管理器中杀死名为 python 的进程。如果你觉得停止通知有任何困难,请在这篇文章的评论部分发表你的困难。
其他可以使用这种方法的领域
- 每日通知吃药。
- 每小时通知喝水。
更多的是,如何使用这个应用程序完全取决于你。
结论
我希望这篇文章引起了您创建自己的定制桌面通知应用程序的兴趣。这个应用程序适用于任何操作系统,无论是 Windows、Linux 还是 Mac。如果您想要一个更简单的桌面通知应用程序,请在本文的评论部分提问
感谢您的阅读😄过得愉快
创建哑铃图以直观显示 R 中的组差异

冠状病毒(也称为新冠肺炎)是一种疫情。截至本文撰写之时,已有近 6000 人死亡,另有 15 万人(T2)被感染。所有迹象似乎表明,病毒只是在增长。
但是一些团体不像其他团体那样担心新冠肺炎。昆尼皮亚克大学最近的民调显示,对冠状病毒的担忧与个人的党派身份、年龄和种族有关。
让我们想象一下,看看差异有多明显。我使用哑铃状点状图,因为它们是可视化两个群体(例如共和党和民主党)之间差异的一些最有力的工具。
政治派别
与民主党人相比,共和党人对冠状病毒的担忧要少得多。这在两个方面是正确的。首先,关于被感染的担忧:

当我们关注新冠肺炎会不会扰乱一个人的生活时,情况也是如此:

看第一个图,我们注意到共和党人说他们“根本不担心”冠状病毒感染他们或他们认识的人的可能性是民主党人的三倍。相比之下,民主党人说他们“非常担心”同样风险的可能性几乎是共和党人的三倍。
第二幅图向我们展示了对破坏的恐惧的类似趋势:四分之三的民主党人担心(非常或有点)新冠肺炎会破坏他们的日常生活,相比之下,只有 38%的共和党人担心。虽然 26%的民主党人不担心分裂,但 61%的共和党人也是如此。
年龄
年龄和对冠状病毒的恐惧也有关系。


这些图表显示,不同年龄的人在担忧方面存在显著差异,但对分裂的恐惧比对感染的恐惧更普遍。第一个情节表明每个年龄段的人都害怕新冠肺炎会打乱他们的日常生活;尽管年轻人表达这种情绪的频率较低。第二个情节大多数 50 岁以下的人并不担心新冠肺炎感染的可能性。年龄较大的受访者则相反;65 岁及以上的人更有可能受到感染风险的影响(62%对 37%)。
为什么是哑铃情节?
哑铃图是分组条形图的替代方法。像条形图一样,它们显示了人群之间的差异,并且更有力地代表了两个群体之间的 T2 距离。他们经常被调查研究公司使用,如皮尤研究中心,如这个例子所示:

虽然条形图需要八个条来可视化上面的每个数据点,但哑铃点图在四条线上显示八个点,减少混乱并强调组之间的差异。
这里有另一个例子,这次来自 Axios (可视化 2017 年 1 月至 10 月总统不支持率的变化):
这个伪哑铃情节(端点怪异的哑铃;别捡那一边!)有 50 个‘组’(美国各州),但只有两个结果(1 月和 10 月)。在这种情况下,哑铃图远远优于组合条形图,因为它强调两个时间段之间的差异,并且它使用的对象比条形图少(50 条线而不是 100 条线)。
从上面的例子中得到一个关键的教训:如果利益的比较是在两个群体之间(例如,共和党和民主党),或者如果利益的结果是双重的(例如,“关注”和“不关注”),点状图是可视化数据的一种更好的方式。
让我们在 R 中制造它!
现在是时候做自己的哑铃点状图了。我们将创建这个,即:

作为参考,我使用的数据如下所示:

很简单,对吧?顺便说一下,它来自这里。
这个过程依赖于 Bob Rudis 的ggalt包和geom_dumbbell函数,它们完成了大部分繁重的工作。本教程主要是在这里找到的 Rudis 的代码的一步一步的再创造。
为了方便起见,在开始之前,让我们先定义一些东西:
blue <- "#0171CE"
red <- "#DE4433"
除了颜色,我们还创建了一个 hack-y 函数,允许我们有选择地标记点(再次感谢 Bob Rudis 的这个):
percent_first <- function(x) {
x <- sprintf("%d%%", round(x*100))
x[2:length(x)] <- sub("%$", "", x[2:length(x)])
x
}
第一步:准系统
我们从一个基本的ggplot对象开始。在geom_segment中,我们定义了伪网格线(每个关注“级别”一条)。
library(ggplot2)
library(ggalt)
library(tidyverse)
ggplot() +
geom_segment(data=infected, aes(y=concerned, yend=concerned, x=0, xend=.5), color="#b2b2b2", size=0.15)
这里,geom_segment创建了大小为 0.15 的灰色线条。线条的跨度从 0 到 0.5。这根据您的数据而变化;因为我们正在处理的最大数字是. 43(代表 43%的民主党人),所以我们右侧的界限可以是 0.5;这也为我们稍后创建的差异列留出了空间。

然后,geom_dumbbell读入我们的数据并创建哑铃:我们指定每个哑铃的开头 ( x)代表共和党,而结尾 ( xend)对应民主党。其他规格影响伴随的线和点。
geom_dumbbell(data=infected, aes(y=concerned, x=rep, xend=dem),
size=1.5, color="#b2b2b2", size_x=3, size_xend = 3, colour_x = red, colour_xend = blue)
该代码创建了以下情节:

我们已经可以开始看到最终版本的框架:每个哑铃代表一个关注级别,并可视化共和党和民主党在该级别的比例。
第二步:标签
下一步是创建“共和党”和“民主党”标签(以防颜色不够,或者图像是黑白的!).
我们可以用下面的代码创建标签:
geom_text(data=filter(infected, concerned=="Very concerned"),
aes(x=dem, y=concerned, label="Democrats"),
color=blue, size=3, vjust=-1.5, fontface="bold", family="Lato") +
geom_text(data=filter(infected, concerned=="Very concerned"),
aes(x=rep, y=concerned, label="Republicans"),
color=red, size=3, vjust=-1.5, fontface="bold", family="Lato")
希望这段代码非常直观。因为我们只显示标签一次,所以我们在geom_text的data参数中指定一个过滤器。如果我们想只显示底层关注的标签,我们可以指定data=filter(infected, concerned=="Not concerned at all")。
我们将每个点标上各自的政治归属,并根据点的颜色指定颜色。剩下的只是对文字的小美化。

我们还必须为值添加直接标签,以便每个组的确切百分比清晰可见:
geom_text(data=infected, aes(x=rep, y=concerned, label=percent_first(rep)),
color=red, size=2.75, vjust=2.5, family="Lato") +
geom_text(data=infected, color=blue, size=2.75, vjust=2.5, family="Lato",
aes(x=dem, y=concerned, label=percent_first(dem)))
在这里,我们利用我们之前定义的函数percent_first,因为我们只希望百分比出现在第一个数字上(以减少混乱)。其余的标签只是代表百分比的数字。这里的语法是简单的语法,应该为ggplot用户所熟悉。它会创建以下输出:

第三步:差异栏
最后,我们想帮助我们的观众看到民主党和共和党之间的差异到底有多明显。我们通过差异列来实现这一点。
geom_rect(data=infected, aes(xmin=.5, xmax=.6, ymin=-Inf, ymax=Inf), fill="grey") +
geom_text(data=infected, aes(label=paste0(diff*100, "%"), y=concerned, x=.55), fontface="bold", size=3, family="Lato") +
geom_text(data=filter(infected, concerned=="Very concerned"),
aes(x=.55, y=concerned, label="Difference"),
color="black", size=3.1, vjust=-2, fontface="bold", family="Lato") +
scale_x_continuous(expand=c(0,0), limits=c(0, .625)) +
scale_y_discrete(expand=c(0.2,0))
这里,我们首先创建一个带有geom_rect的灰色矩形。它垂直跨越了整个图表,这就是为什么ymin和ymax的范围从负无穷大到正无穷大。接下来,我们根据差异列创建标签。我们根据关注程度(我们的 y 轴)对它们进行定位。最后,我们扩展了图表的边界,使它看起来更漂亮一些:

第四步:标题、标签和说明
最后,让我们添加标题、副标题、题注和轴标签:
labs(x=NULL, y=NULL, title="Republicans are less worried about COVID-19",
subtitle="How concerned are you that you or someone you know will be infected with the coronavirus?",
caption="Source: Quinnipiac University Poll, March 9, 2020\. Q27\n\nDesign: Connor Rothschild")

那是我们的阴谋!可惜它有点丑。让我们在最后一步解决这个问题。
步骤 5:美化
使用theme参数进行美化。
theme_bw(base_family="Lato") +
theme(
panel.grid.major=element_blank(),
panel.grid.minor=element_blank(),
panel.border=element_blank(),
axis.ticks=element_blank(),
axis.text.x=element_blank(),
plot.title=element_text(size = 16, face="bold"),
plot.title.position = "plot",
plot.subtitle=element_text(face="italic", size=12, margin=margin(b=12)),
plot.caption=element_text(size=8, margin=margin(t=12), color="#7a7d7e")
)
在指定了我们的基本ggplot主题theme_bw之后,我们使用theme()来指定一系列的参数。
为了简化,上面的代码:
- 删除网格线(
panel.grid.major,panel.grid.minor) - 移除面板边框(
panel.border) - 删除轴记号和轴文本(
axis.ticks、axis.text.x) - 定位轴绘图、副标题和标题,并设置它们的样式(
plot.title、plot.title.position、plot.subtitle、plot.caption)。
我们的最终产出:

总结
我们的过程看起来像这样:

上述可视化的代码,以及底层数据集和输出,可以在这里找到。
感谢阅读!
康纳·罗斯柴尔德的最新推文(@CL_Rothschild)。数据科学和公共政策。使用内部字体系列…
twitter.com](https://twitter.com/CL_Rothschild)
原载于我的 博客 。
创建有效的比例数据可视化
在各种数据集规模下,查看个体对整体的贡献以及随时间变化的最佳方式—(包括简单、直观的演示、代码和数据)

比例的各种可视化
绘制整体的比例可能是数据可视化中最常见的任务之一。例子包括幸福度、经济指标或犯罪的地区差异,投票模式、收入或支出的人口统计学差异,或者企业各部分对其底线的贡献。通常,数据还描述了随时间的变化,时间可能是几个月、几个季度、几年或几十年。
尽管它们都与整体的比例有关,但通常没有一种放之四海而皆准的方法适用于所有情况。
在这篇文章中,我描述了我认为的交流整体比例的有效技巧,以及随着时间的推移对它们的改变。我还将探讨随着数据点或数据系列数量的变化,图表有效性的变化。
和往常一样,这篇文章还将包括一些例子,这样你就可以跟随并创建你自己的、有趣的数据可视化。
对于代码,我将使用著名的 Gapminder 数据集,以及上赛季多伦多猛龙队篮球投篮份额的一些数据。这些只是显示比例的数据集的例子,所以你不需要知道任何关于经济学或篮球的知识就能跟上。
在开始之前
数据
我将代码和数据包含在我的git lab repo here(viz _ proportions目录)中。所以请随意使用它/改进它。
包装
我假设您熟悉 python。即使你相对较新,这个教程也不应该太难。
你需要pandas和plotly。用一个简单的pip install [PACKAGE_NAME]安装每一个(在你的虚拟环境中)。
想象简单的比例
加载和检查数据
很方便的是,plotly包提供了一些玩具数据集供我们使用, Gapminder 数据集就是其中之一。我们可以加载:
import plotly.express as px
gap_df = px.data.gapminder()
用gap_df.info()和gap_df.head()检查数据,我们会看到它显示了每年多个国家的数据。
它包括人口和人均 GDP——所以让我们将两者相乘得到 GDP 数据。
gap_df = gap_df.assign(gdp=gap_df['pop'] * gap_df['gdpPercap'])
仅可视化一年的数据
对于第一次观想,让我们比较几种不同类型的图表。最初的数据包括 142 个国家 1952 年的数据。让我们简化数据,按大洲收集数据,并且只将最近一年的数据收集到cont_df中。
year_df = gap_df[gap_df.year == max(gap_df.year)]
cont_df = year_df.groupby('continent').agg({'gdp': 'sum'})
cont_df.reset_index(inplace=True)
这里,数据帧按洲分组,并重置索引,因为在 Plotly Express 中处理“平面”数据帧更容易。
现在可以使用 Plotly Express 绘制数据。绘制这些基本图形的代码非常简单。我注意到,对于气泡图,我添加了一个名为dataType的任意变量,这样它就可以用来在 Y 方向上对齐气泡。
# Pie chart
fig = px.pie(cont_df, values='gdp', names='continent')
fig.show()
# Bar chart
fig = px.bar(cont_df, color='continent', x='continent', y='gdp')
fig.show()
# Horizontal bar chart - stacked
fig = px.bar(cont_df, color='continent', x='gdp', orientation='h')
fig.show()
# Bubble chart
fig = px.scatter(cont_df.assign(dataType='GDP'), color='continent', x='continent', y='dataType', size='gdp', size_max=50)
fig.show()
我在这里收集了结果:

简单比例数据的图表类型比较
除了柱形图之外,所有的图表都不能很好地表明相对大小。
当数据点的大小接近时,如亚洲、美洲、欧洲的 GDP 数据,堆积条形图和饼图不允许数据点之间的简单比较,因为它们是从不同的参考开始的。
饼状图也有问题,因为众所周知,角度的差异很难准确感知,所以我们会忽略它们。
气泡图稍好一些,但是因为气泡的大小与数据集的大小有关,所以半径的差异变得比柱形图小(小一个平方根)。
当我们增加一个时间维度时会发生什么?
随着时间的推移可视化数据
对于这一部分,我们需要一个包含多年数据的数据框架。我们可以使用整个数据集,但让我们保持简单,只使用少量年份的数据。
数据集包含多个年份,但不是每个年份。我们可以使用gap_df.year.unique()来查看哪些年份的数据可用,选择 1985 年以后的年份,这是五个不同的年份。
我们的汇总数据框架可以构建如下:
mul_yrs_df = gap_df[gap_df.year > 1985]
mul_yr_cont_df = mul_yrs_df.groupby(['continent', 'year']).agg({'gdp': 'sum'})
mul_yr_cont_df.reset_index(inplace=True)
groupby方法将创建一个多索引数据帧,它可以被认为是(continent, year)的嵌套索引(如果您想了解更多关于层次/多索引的知识,这是一个很好的资源)。然后,在我们绘制它们之前,指数再次变平。
# Bar chart
mul_yr_cont_df = mul_yr_cont_df.assign(yrstr=mul_yr_cont_df.year.astype(str))
fig = px.bar(mul_yr_cont_df, color='continent', y='gdp', x='yrstr', barmode='group')
fig.show()
# Horizontal bar chart - stacked
fig = px.bar(mul_yr_cont_df, color='continent', x='gdp', orientation='h', y='yrstr')
fig.show()
# Bubble chart
fig = px.scatter(mul_yr_cont_df, y='continent', x='yrstr', color='continent', size='gdp', size_max=50)
fig.show()

分组列

堆积条形图

泡泡图
有了这些,前面的属性仍然适用于在条形图中看到相对比例的容易程度。但是,通过在数据中增加另一个维度,可以进行新的观察。
虽然每个系列的大小仍然很难比较,但堆积条形图能够显示整体样本大小的变化,这一点很有价值。
就分组条形图而言,沿 x 轴分组变得很重要,因为不同组之间的比较变得更加困难,而同一组内的比较仍然很容易。尝试绘制和比较这两个:
fig = px.bar(mul_yr_cont_df, color='continent', y='gdp', x='yrstr', barmode='group')
fig.show()
fig = px.bar(mul_yr_cont_df, color='yrstr', y='gdp', x='continent', barmode='group')
fig.show()

对各大洲的比较进行优先排序

跨年度优先比较
在上图中,跨年度的比较优先于跨洲的比较,反之亦然。
对于跨两个轴的比较,气泡图将数据排列在网格中,这使得跨两个维度比较变化更加容易。
如果气泡图中的大小变化不够明显,条形图的网格(子图)可能会更好:
fig = px.bar(mul_yr_cont_df, color='continent', facet_col='continent', x='gdp', orientation='h', facet_row='yrstr')
fig.update_yaxes(showticklabels=False)
fig.show()

网格支线剧情
太好了。但是通常每个轴上有 5 个数据点。那么,如果级数增加会怎么样呢?
可视化更大的数据集
让我们针对 12 年数据集的所有数据重复这些图(为简洁起见,此处未显示代码—参见 git repo)。




在这里,我们已经开始看到分组条形图的一些空间限制。不同组之间的比较也变得越来越困难,因为单个条形在高耸的彩色条形森林中迷失了,相邻条形的相对变化欺骗了我们的大脑。
尽管这个数据集在视觉上随着规模相对很好地缩放,这得益于 GDP 随时间的增长,但很容易看出其局限性。
最后一点,让我们来看看一个更大的、有序度更低的数据集。
奖励剧情:篮球投篮股份(2019 多伦多猛龙)
在一个 NBA 赛季的 82,48 分钟的规定时间里,一支球队要投篮 7000 次。在多伦多猛龙队的情况下,他们有 14 名球员至少获得 1%的投篮命中率。由此产生的 15 名“球员”(14 + 1 名“其他人”)如下所示,分为每 2 分钟一段。
这个数据集也与上面略有不同,因为我将展示百分比的分布。
在上述每种情节类型中,它们看起来是什么样的?

分组条形图

堆积条形图

网格条支线剧情

泡泡图
随着数据点在两个维度上变得越来越多,并且随着最大值与最小值之比的增加,网格中的气泡图开始发挥作用。
在气泡图中,条形图中 1 到 25 的高度变化变成了 1 到 5 的半径变化。事实上,尺寸的变化转化为半径的变化有效地压缩了视觉差异,并有助于显示更大的范围。它(以及条形子图方法)还有一个额外的优势,即能够将第四个变量演示为颜色,因为空间位置指定了它的两个维度。
您可能会发现,随着数据集变大,尤其是数据集变大,我更喜欢这种类型的子图方法。但是正如你之前看到的,在其他情况下,其他类型的观想效果明显更好。
那么——选择什么呢?
你可能已经看到了这一点,但在我看来,没有“一刀切”的方法。我甚至还没有开始在视觉比例方面触及这个领域的表面——比例、使用颜色的不同方法、符号类型、利用整体分布形状和突出比例等。
但我希望这些例子至少对你了解不同类型的观想有用,以及它们的功效如何随着样本大小而变化。我发现没有什么比练习更能真正学习数据可视化并变得更好了。所以,选择一个数据集,然后去做——你对这个主题领域越熟悉越好。
如果你喜欢这个,比如说👋/在 twitter 上关注,或关注更新。我还写了这篇关于我最喜欢的数据可视化书籍的文章,如果你以前没有读过的话:
如果没有交流,好的分析没有什么意义。数据可视化会有所帮助。以下是我对…的建议
towardsdatascience.com](/create-impactful-data-visualizations-with-these-books-ca9fbfecfde5)
同样,这也是一个大众的最爱:
[## 如何用 Python 可视化数据中的隐藏关系 NBA 助攻分析
使用交互式快照、气泡图和桑基图操纵和可视化数据,使用 Plotly(代码和数据…
towardsdatascience.com](/how-to-visualize-hidden-relationships-in-data-with-python-analysing-nba-assists-e480de59db50)
下次见!
使用 Gretel.ai 和 Python 在您的云中创建高质量的合成数据
创建差异私有、合成版本的数据集;同时满足法规遵从性要求,将敏感数据保留在您批准的环境中。
无论您关注的是医疗保健行业的 HIPAA 、金融行业的 PCI ,还是保护消费者数据的 GDPR 或 CCPA ,能够在不需要与 SaaS 服务合作的数据处理协议 (DPA)的情况下开始构建,可以显著减少启动项目和开始创造价值所需的时间。今天,我们将通过一个示例,在本地(您的云或内部)配置中使用 Gretel.ai 来生成高质量的合成数据和模型。

来源:设计单元格,通过 iStockPhoto
设置您的本地环境
要开始,你只需要三样东西。
- 要以 CSV 或 Pandas 数据帧格式合成的数据集
- Gretel.ai API key(免费)
- 本地计算机/虚拟机/云实例
推荐设置。我们推荐以下硬件配置:CPU:合成记录生成推荐 8+ vCPU 核。GPU:建议培训使用支持 CUDA 10.x 的 Nvidia Tesla P4。RAM: 8GB+。操作系统:Ubuntu 18.04 支持 GPU,或 Mac OS X(Mac 不支持 GPU)。
GPU 加速参见 TensorFlow 优秀的设置指南。虽然 GPU 不是必需的,但在 GPU 上进行训练通常比在 CPU 上快至少 10 倍。或者在 CPU 上运行并获取一个☕.
生成 API 密钥
使用 API 密匙,您可以免费访问 Gretel 公共测试版的高级功能,这些功能增强了我们的开源库用于合成数据生成,具有改进的字段间相关性、自动化合成数据记录验证以及合成数据质量报告。
用 Github 或谷歌邮箱登录或创建一个免费账户到 Gretel.ai 。点击右上角的个人资料图标,然后点击 API 键。生成一个新的 API 令牌并复制到剪贴板。

在 https://console.gretel.cloud 生成 API 密钥
设置您的系统并安装依赖项
我们建议为您的运行时设置一个虚拟 Python 环境,以保持您的系统整洁,在这个示例中,我们将使用 Anaconda 包管理器,因为它对 Tensorflow 、GPU 加速和数千个数据科学包提供了强大的支持。你可以在这里下载并安装 Anacondahttps://www.anaconda.com/products/individual。
创建虚拟环境
conda install python=3.8
conda create --name synthetics python=3.8
conda activate synthetics # activate your virtual environment
conda install jupyter # set up notebook environment
jupyter notebook # launch notebook in browser
安装所需的 Python 包
将 gretel-synthetics 、Tensorflow、Pandas 和 Gretel helpers(需要 API 密钥)等依赖项安装到新的虚拟环境中。将下面的代码样本直接添加到您的笔记本中,或者从 Github 下载完整的合成笔记本。
训练模型并生成合成数据
将源文件从 CSV 加载到 Pandas 数据框架中,添加或删除任何列,配置训练参数,并训练模型。如果可能,我们建议至少有 5,000 行训练数据。
比较源数据集和合成数据集
使用 Gretel.ai 的报告功能来验证合成数据集是否包含与原始源数据相同的相关性和洞察力。
# Preview the synthetic Dataframe
bundle.synthetic_df()# Generate a synthetic data report
bundle.generate_report()# Save the synthetic dataset to CSV
bundle.synthetic_df().to_csv('synthetic-data.csv', index=False)
下载您的新合成数据集,探索合成数据报告中的相关性和见解!

比较源数据集和合成数据集之间的洞察力
想从头到尾贯穿一遍?
在 Github 上下载我们的漫游笔记本,将笔记本加载到您的本地笔记本服务器中,连接您的 API 密匙,并开始创建合成数据!
编辑描述
colab.research.google.com](https://colab.research.google.com/drive/1EcPshb2mrWMpZjs7rADOIJT0azhZu_Ye?usp=sharing)
结论
在 Gretel.ai ,我们对使用合成数据来增强训练集以创建 ML 和 ai 模型的可能性感到非常兴奋,这些模型可以更好地概括未知数据,并减少算法偏差。我们很乐意听到您的使用案例——欢迎在评论中联系我们进行更深入的讨论, twitter ,或 hi@gretel.ai 。比如gretel-synthetics?给我们一个 Github 上的⭐!
用这些书创建有影响力的数据可视化
如果没有交流,好的分析没有什么意义。数据可视化会有所帮助。以下是我对 2020 年增强 dataViz 的建议。

罗伯特·阿纳奇在 Unsplash 上的照片
数据可视化可能是数据工作迷人的公众形象。
它们无所不在。我们都经常接触到我们最喜欢的网站、体育广播甚至广告上的图表和数据。
与数据科学的复杂性、数据挖掘的庞大数量以及数据新闻的冗长相比,数据可视化是简单、可访问和简短的。
数据可视化也吸引潜在的从业者;可能是因为 T4 看起来很容易。DataViz 输出看起来更像是我们可以创建的东西。我们都在 Excel 里画过图表,在 PowerPoint 里用过。会有多难呢?
但事实是,创建良好的数据可视化并不容易。要做到这一点,数据可视化必须准确,视觉冲击力强,有说服力。这是一个很高的标准(图表),需要很好地掌握多个领域,如统计学、视觉传达、编程,甚至人类的感知和偏见。
在这篇文章中,我整理了几本书,我认为这些书将有助于开始数据可视化。此外,我试图保持列表的多样性,涵盖每个相关主题领域的一些内容。
如果你认为我错过了什么,请在评论或推特上告诉我!
注:这些书有些是免费的(这个社区是不是很精彩?).其他人的亚马逊是附属链接,这意味着在你没有额外费用的情况下,我会得到一小笔佣金。
数据可视化—概述
数据可视化基础(克劳斯·威尔基)

如果你不知道从哪里开始,这是一个很好的地方。
威尔基的书是那种适合用作参考手册,但天生可读的稀有书籍之一。我发现自己只是一章接一章地阅读,因为我发现这种经历既愉快又有启发性。
我不应该感到惊讶的是,一本关于数据可视化的书编排得很好,并以经济的方式传达了它的思想,但威尔基做得很好。作为一个简单的例子,威尔基将观想例子标记为“丑陋”或“糟糕”,这看起来是一个如此简单、明显的想法,但却真正抓住了你的注意力,让你的思维转向“为什么”以及应该如何去做。
它没有杂乱,也没有成本(如果你愿意的话),因为威尔基已经将整个手稿作为一个精美的网站在线提供。
真实的艺术:用于交流的数据、图表和地图(阿尔贝托·开罗)

Alberto Cairo 几乎是数据可视化领域的名人。他有新闻记者和学术证书,他在社交媒体上相当活跃,经常称赞他人的良好工作,并领导反对错误信息的斗争。
在我看来,艾伯特·开罗关于数据或数据可视化的任何书籍都不会错。
如果要我选一个的话,我会选这个。他的第一本书更像是一本介绍性的书,倾向于在光谱的抽象部分多躺一会儿,他的最新的书是针对观想的消费者而不是创造者。这个对我来说可能是最合适的,因为它稍微更实用(在我看来),并且针对…数据可视化的供应方面。
在亚马逊上有售
用数据讲故事(科尔·努斯鲍默·克纳弗里克)

这本书的一切都很谦逊,从简单的标题到严肃的封面。
这是这本书魅力的一部分。《用数据讲故事》是为商业专业人士写的,是一本很好的通才书籍,不像其他一些书那么专业,或许也不那么吓人。
我会向那些没有太多统计或数据分析背景的人推荐这本书,但可能不会向那些在数据相关领域有经验的人推荐。
在亚马逊上有售
好的图表:制作更聪明、更有说服力的数据可视化的 HBR 指南(斯科特·伯里纳托)

不要让标题中的“HBR”这几个字让你失去兴趣。这不是一本关于数据可视化基础知识的普通、最低标准的书。
虽然毫无疑问,它是为门外汉编写的,但 Berinato 并没有忽略历史和力学,或者数据可视化科学。
由此产生的产品是一个有效的,美丽的书,为从业者,管理者,或外行。Berinato 专注于创建有助于决策的有目的的图表,这在他的工作中得到了体现。
我经常发现一本“以业务为中心”的技术书籍往往会简化它,但在这种情况下,它有助于将精力用于实现目标和帮助决策者。
在亚马逊上有售
数据可视化和编程
Python 数据科学手册(Jake VanderPlas)

对于大多数从事数据可视化工作的人来说,他们的工作很可能也包括争论数据。
Python 是我选择的数据科学和分析语言,这意味着我经常使用包numpy和pandas。
这本书很好地介绍了这两者——尽管标题有些吓人,涉及到“数据科学”,但如果你熟悉 Python 的话,这是关于这个主题的较容易的书籍之一。免费提供!
网络交互式数据可视化(斯考特·玛瑞)

D3.js 是可视化库,面向希望创建定制的交互式视觉效果的专业人员。
基于 JavaScript 的之上,它确实有一个陡峭的学习曲线。以至于许多更容易使用的高级库都在它的上面(比如 Vega Lite 或 Plotly)。**
如果你想或者需要使用 D3.js,这本书是一个很好的起点。Murray 引导你熟悉 D3.js 的旅程,尽管这是一个漫长的旅程,但他设法注入足够的幽默和小胜利来使它变得更容易。他还让这本书在网上免费提供,同时提供了要遵循的代码。
不,简单地说,这本书不会让你成为 D3.js 的大师,然而这是任何编程语言或库的真理。但这可能会节省你大量的时间和悲伤。
在这里可以免费在线购买 |也可以在亚马逊上购买
背景材料
赤裸裸的统计:从数据中剥离恐惧(查尔斯·惠兰)

我认为对统计学有良好的直觉理解在现代社会中是非常重要的。
在我看来,这对于任何一个“知识工作者”来说都是适用的,如果你做任何与数据有关的事情,对统计学的扎实掌握是必须的。
不幸的是,我也参加过一些统计学课程,我知道这些课程大多以最疏远的方式教授。所以当我看到这本书的时候,我一定要把它推荐给每个人。
对大多数人来说,统计学不应该是关于复杂的数学符号和 p 值的深奥讨论,或者哪种分布最适合。它是关于对我们观察世界的直观理解。反过来,它帮助我们剥去其他人试图通过扭曲统计数据来讲述的谎言,同时另一方面帮助我们讲述适合自己的故事。强烈推荐。
可从亚马逊购买
完整的色彩调和,潘通版(利阿特丽斯·艾斯曼)

如果你没有像我一样的设计背景,你对颜色的理解可能不会像你希望的那样好。
虽然我理解颜色背后的物理学,并对不同的颜色有一些初步的了解,但这本书帮助我理解了对颜色的情感感知。
一些描述可能看起来有点不准确,因为相当一部分框架和语言是情绪化的;然而,我认为她或多或少地捕捉到了人们对颜色的反应,以及为什么颜色会被这样使用。
可从亚马逊购买
奖金簿:数据相邻
毁灭计划:改变了我们想法的友谊(迈克尔·刘易斯)

在书店找到一本迈克尔·刘易斯的书对我来说是个坏消息。
主要是因为我不可避免地坐立不安,游离于我对刘易斯的书的热爱的本能记忆中,比如《闪电侠》和《短暂的时光从我身边流逝》。
我推荐这本书,因为简单地了解行为心理学是一种丰富的经历,还因为休斯顿火箭队总经理达里尔·莫雷的章节本身就值得入场费。
如果你对体育和数据感兴趣,读读那一章,想想如果有一个像莫雷这样的老板,他的任务是用最好的数据做出最好的决定,那该有多好。此外,刘易斯是我们这个时代最好的作家之一,能够将一个看似平凡的主题转化为叙事黄金。
在亚马逊上有售
显然,从几十本好书中挑选几本并不是一件容易的事情,但是我希望至少这些能帮助你开始。我打算不时更新这些,所以如果你认为我做了一些惊人的遗漏,请务必让我知道。
使用 GitHub 页面为您的项目创建登录页面
使用自定义项目网站展示您的作品

Igor Miske 在 Unsplash 上拍摄的照片
我来自一个实验科学的背景,在那里我们要处理大量自制的实验装置和数据分析脚本。通常,这样做的结果可能是糟糕的文档和难以使用的代码,尤其是在最初的研究生(编写它的人)已经毕业并离开之后。出于这个原因,当我在研究生院研究期间开发一些数据分析脚本时,我决定尽我所能尝试并记录/演示它,以便任何未来的用户都可以直观地使用它。我努力的结果就是这个登陆页面。

我能够用 GitHub Pages 生成这个网站,GitHub Pages 是一种服务,允许您轻松地为您的存储库托管一个静态网站。这样做非常简单,您的网站将位于 URL:
https://<username>.github.io/<repository_name>
1。创建一个孤立分支
为了简单起见,我们不希望克隆我们的master分支的用户也看到将与我们的项目网站相关联的所有 HTML/CSS/JS 文件。为了解决这个问题,我们可以使用一个叫做“孤儿分支”的东西——本质上是一个位于树的根部、没有先前提交的分支。然后,通过将我们所有的网站文件保存在孤立分支中,当库被克隆时,默认情况下只有master上的文件会被显示(尽管任何人如果愿意,仍然可以访问网站分支)。
我们创建自己的孤立分支,用下面的命令将其命名为gh-pages:
git checkout --orphan gh-pages
2。清算 **gh-pages** 分支
这是我第一次做这个的时候发现最恐怖的部分。为了清除gh-pages分支,您将从文件夹中删除所有内容。放心吧,你的master分科档案没了!使用以下命令:
git rm -rf .
你会注意到所有的文件都将从你的本地工作目录中消失,这就是我第一次这么做的原因。同样,不要担心,一切都会好的!
3。添加网页文件
现在,将您的index.html文件,以及任何 CSS 样式表、Javascript 和您的网站运行所需的其他资源添加到您的本地工作目录中。现在准备并提交您的更改:
git add *
git commit -m "Commit Message"
最后,我们希望确保我们将我们的变更推到适当的分支(gh-pages)。
git push origin gh-pages
4。建立 GitHub 页面
在线导航到你的 GitHub 库,进入设置。向下滚动时,您会注意到一个标题为“GitHub Pages”的部分。在标题为“Source”的区域下,您会看到一个下拉菜单,您可以使用它来选择构建您的网站的分支。我们将选择gh-pages。

等几分钟,然后砰!你的网站应该是活的!导航你的浏览器到https://<username>.github.io/<repo_name>看你的精彩创作。
5。为分支机构建立单独的目录
随着您继续编辑您的网站和源代码,您会很快注意到您必须在两个分支之间不断切换:
# Switch to master branch
git checkout master# Switch to gh-pages branch
git checkout gh-pages
虽然简单,但过一段时间后这可能会变得很麻烦——幸运的是,我们可以使用名为worktree的特性为每个分支创建单独的目录。
首先,让我们创建一个单独的、与我们的存储库同名的新目录,或者清除我们的本地工作目录。如果我们清空当前目录,我们希望删除所有的git跟踪信息,我们可以通过以下方式来实现:
# Remove git tracking
rm -rf .git*
现在,让我们将我们的存储库重新克隆到子目录中。我们称这个目录为source,它将是我们保存所有源代码的地方。
git clone https://github.com/<username>/<reponame> source
您会注意到现在有了一个名为source的文件夹,其中包含了来自master分支的所有文件。现在让我们创建一个名为gh-pages的新目录,它将存放我们所有的网站文件:
mkdir gh-pages
导航到源文件夹:
cd source/
现在,我们使用worktree并使我们的gh-pages目录对应于远程gh-pages分支。
git worktree add ../gh-pages gh-pages
你完了!现在,你会注意到,当你转到gh-pages目录时,你将只看到gh-pages分支上的文件,如果你运行一个git branch命令,你将看到当你在source目录时你在master上,当在gh-pages目录时你在gh-pages上。
您现在可以同时自由编辑您的存储库网站和源代码,并且您在 GitHub 上有一个非常棒的项目登录页面!
结束语
感谢您的阅读!你可以在我的个人 GitHub 页面看到我的一些作品。我感谢任何反馈,你可以在 Twitter 上找到我,并在 LinkedIn 上与我联系以获取更多更新和文章。
创建 ML:一个用于训练神经网络的 GUI
让我们用 3 行代码创建一个狗和猫的分类器。
几周前,我买了一台新的笔记本电脑——2019 年的 MacBook Pro,从那以后我就喜欢上了它。很自然地,我开始试验 Swift T1 和 T2 Xcode T3,主要是为了创建一些虚拟的 iOS 应用。在那里我发现了 Create ML——一个用于训练定制神经网络的 GUI 工具。

照片由托马什·斯坦尼斯拉夫斯克在 Unsplash 拍摄
这里有一个直接来自苹果官方文档的简短声明:
将 Create ML 与 Swift 和 macOS playgrounds 等熟悉的工具配合使用,在 Mac 上创建和训练定制的机器学习模型。您可以训练模型来执行任务,如识别图像、从文本中提取含义或查找数值之间的关系。[1]
很好。所以你可以看到,它不仅仅是像我们今天要做的图像分类。
首先要注意的是,对于大多数用户来说,创建 ML 肯定会有一个巨大的缺点——这是一个苛刻的要求:你需要在 macOS 上运行。
如果你没有苹果电脑,这并不是世界末日,因为像 MacInCloud.com 这样的解决方案已经存在。我还没有亲自测试过它们,所以我不能保证你会有一个完美流畅的体验——但总比没有好。
所以概括一下,如果你想继续,你需要运行 macOS,并且安装最新版本的 Xcode 。
这篇文章的结构如下:
- 数据集下载
- 3 行来训练他们
- 模特培训
- 模型评估
- 模型保存
- 结论和下一步措施
简单提一下,在下一篇文章中,我们将创建一个 iOS 应用程序,并将我们的训练模型链接到它。 GitHub repo 已经存在,可以随意查看。
数据集下载
如前所述,我们将制作一个狗和猫的图像分类器,数据集可以从这里下载。
如果您已经下载并解压缩了它,那么在根文件夹中,您将拥有以下结构:
├── test
│ ├── cat
│ └── dog
└── train
├── cat
└── dog
这里有两件事你必须知道:
- 在训练和测试文件夹中的子文件夹名称必须相同
- 预测的类别名称将从子文件夹名称中推断出来——因此这里的猫和狗
还在跟踪?太好了,让我们在开始训练之前做好一切准备。
3 行来统治他们
我们现在可以打开 Xcode 并创建一个新的游乐场——一个用于 macOS 的空白游乐场:

随意命名,点击下一个。我们现在看到了以下屏幕:

太好了!在左边部分,我们将编写我们的代码,在右边部分,我们将训练我们的模型。
我们现在可以删除该占位符代码,并输入以下 3 行代码:
import CreateMLUIlet builder = MLImageClassifierBuilder()
builder.showInLiveView()
您的屏幕应该是这样的:

不要担心弃用警告,因为代码会工作得很好。现在,我们可以单击代码下方的蓝色播放按钮。几秒钟后,您将看到以下内容:

就这样,我们可以开始训练了!
模特培训
好了,现在你唯一要做的就是将 train 文件夹拖到这个 Drop Images 开始训练部分:

训练过程将立即开始,由于我们有超过 20K 的训练图像,这显然需要一些时间。所以,喝杯咖啡,休息一下,或者看看火车模型。
现在,过了一段时间(在我的机器上大约半小时),模型被训练:

正如我们所看到的,它在训练集上表现出色,只需看看它在以前看不到的数据上的表现如何——因此在测试集上。让我们在下一节中探索这一点。
模型评估
要评估测试集上的模型,只需将测试文件夹拖至拖放图像以开始测试部分:

测试过程将大大缩短时间,因为我们只有 2500 张图像用于测试。尽管如此,你也可以休息一会儿,直到它结束。
好了,完成了吗?爽。正如我们所看到的,测试集上的准确率仍然令人印象深刻——98%。

现在我们知道我们的模型已经可以生产了,让我们在下一节探索如何导出它。
模型保存
我们需要保存这个模型,以便以后在我们的 iOS 应用程序中使用。为此,向上滚动模型培训部分并展开下拉列表:

如果您对自动填充的选项感到满意,请点击保存。记住,默认情况下,模型将被保存到 Documents 文件夹中——所以让我们快速验证一下它是否在那里:

厉害!注意。mlmodel 扩展?对于您希望在 iOS 上部署的任何模型,这都是强制性的,所以请记住这一点。
我们今天的工作已经完成了,所以让我们做一个简短的总结。
结论
做完这一切后,你可能想知道这个模型到底是怎么表现得这么好的?苹果官方声明如下:
Create ML 利用了苹果产品内置的机器学习基础设施,如照片和 Siri。这意味着你的图像分类和自然语言模型更小,训练时间更少。[2]
简而言之,这意味着苹果有很多预训练的模型,它只需要调整输出层(也称为迁移学习)。如果你以前用过 ResNet 或者 AlexNet ,你就会知道我在说什么。
但是现在你有了它,大约 30 分钟来训练模型,并在测试集上达到 98%的准确率——对于只有 3 行代码来说非常令人印象深刻。
请继续关注下面的文章,我们将把这个模型整合到一个 iOS 应用程序中。
感谢阅读。
喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。
[## 通过我的推荐链接加入 Medium-Dario rade ci
作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
medium.com](https://medium.com/@radecicdario/membership)
资源
[1]https://developer.apple.com/documentation/createml
[2]https://developer.apple.com/documentation/createml
创建 ML:将模型部署到 iOS 应用程序
让我们创建一个简单的狗与猫的 iOS 应用程序!
几天前,我在 Create ML 部分发表了两篇文章中的第一篇,那篇讨论了收集数据和模型训练的过程。今天我们将会有更多的乐趣,因为在文章的最后,你将会在你的 iPhone 上拥有一个能够对狗和猫进行分类的应用程序(或者模拟器)!

安东尼·乔伦在 Unsplash 上的照片
作者注: 我不是 iOS 开发者,这篇文章大概不会演示最干净的解决方案。然而,它仍然完美地工作着,我发现它值得与我的读者们分享。
如果你错过了第一篇文章,你可以在这里找到它:
让我们用 3 行代码创建一个狗和猫的分类器。
towardsdatascience.com](/create-ml-a-gui-for-training-neural-networks-72bd1d651275)
请记住,您不必完全阅读它,因为模型文件可以在官方的 GitHub repo 中获得。尽管如此,我还是强烈建议你这么做,因为你会发现现在训练图像分类器是多么容易。
跟随的前提依然苛刻:
- 你需要一台苹果电脑(或者使用 MacInCloud.com)
- 最新版本的 Xcode 是必须的
- 你应该对 iOS 开发有所了解(目录结构,如何运行应用…)
如果你没有 iPhone,这很酷,因为这款应用可以在模拟器上运行。在开始编写代码之前,让我们快速浏览一下这个应用程序的最终版本,这样可以让你更有动力:
这篇文章的结构如下:
- iOS 项目创建
- 布局
- 代码
- 让我们运行它
- 结论
所以,事不宜迟,我们开始吧!
iOS 项目创建
启动 Xcode 并选择创建新的 Xcode 项目。在那里,选择单视图应用:

这将打开一个新窗口。在这里,您可以指定应用程序的名称——这样做,并将其他所有内容保留为默认值。点击下一个:

最后一步是将应用程序存储在某个地方—您决定最佳位置:

现在将创建项目。这里我们需要做的最后一步是将我们的模型包含到应用程序中。为此,只需拖动。mlmodel 文件到项目文件:

这一节就讲到这里。在下一个中,我们将为应用程序创建布局。
布局
布局非常简单——我们将在 Main.storyboard 文件中设计它。我的决定是将视图包装在导航控制器中,这样我们就可以在导航栏中设置摄像头按钮。
还有,导航栏有个标题——狗还是猫?
此外,在内容部分,我们有一个基本的 UIImageView 来显示一个图像,在它下面,我们有一个文本视图来显示预测的类。您看不到它,因为默认情况下它是空白的,一旦我们选择一个图像,它就会被填充。
下面是你最后应该有的截图:

如果你有一些开发 iOS 应用的经验,像这样构造简单的 UI 不是问题。我决定不一步一步地展示这个过程,因为这篇文章很快就会变得很乱。非常欢迎你克隆官方回购,卡壳了可以借鉴。
好的,如果你现在已经跟上了,你应该已经完成了布局部分。在下一节中,我们将开始编写一些代码以及管理权限。
代码
在编写任何 Swift 代码之前,我们需要获得用户的照片库许可——转到 Info.plist 并添加如下:

就这样,现在用户可以允许我们访问他/她的图像。我们现在准备写一些 Swift 代码!
我绝不是 Swift 方面的专家,恰恰相反,我认为自己是一个绝对的初学者,但我发现这段代码工作得非常完美。也许它并没有考虑到最佳实践,但是它将适合我们的需要。
以下是我们需要执行的步骤(嗯,主要步骤):
- 导入库
- 为我们的视图声明变量
- 按下相机按钮时显示图像拾取器
- 处理图像拾取器
- 为图像分类声明一个函数
- 图像拾取控制器的链接检测功能
整个代码必须写在 ViewController.swift 文件中。您可以在下面的要点中找到代码,其中的步骤被写成了注释:
这就是关于代码的大部分内容!在下一部分,我们将运行这个应用程序(但我猜你已经知道它是如何执行的——如果你看过视频演示)。
让我们运行它
现在,我们实际上可以选择在哪个设备上运行应用程序。如果您没有 iPhone,您可以从下拉菜单中选择任何模拟器:

按下启动按钮,编译运行需要一分钟左右的时间。在模拟器上,我上网下载了一些免版税的猫狗图片。
一旦你这样做了,打开应用程序来测试它。以下是从我的设备获得的分类:

是的,我们确实有很多未使用的空白,设计也不完美——但这是一篇数据科学相关的文章,而不是 UI 设计相关的文章。不管怎样,今天就到这里,让我们在下一节快速总结一下。
结论
我是 iOS 开发者吗?最肯定不是。在设计和代码质量方面有改进的空间吗?绝对可以。
但是,作为数据科学家,我们没有义务在 UI 设计方面表现出色。我的意思是,你拥有这些技能很好,但这不是强制性的。
这篇文章和之前的 Create ML 文章背后的唯一目标是增加趣味,让你(和我)走出舒适区。编写算法代码并花费数周时间是一回事,但如果你只知道如何使用它,那又有什么意义呢?如果没有好的方法来展示你的作品,那还有什么意义呢?
花点时间想一想。它不必是一个移动应用程序,因为一个简单的网络应用程序与上传组件将只是这个项目的罚款。
感谢阅读。
P.S. 如果模型对你的一些图片分类错误,请告诉我,因为我测试过的每一张图片都被正确分类了。
喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。
[## 通过我的推荐链接加入 Medium-Dario rade ci
作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
medium.com](https://medium.com/@radecicdario/membership)
用 Python 创建音乐推荐系统
推荐系统
熟悉 Tableau 并创建一个协同过滤推荐系统

大家好!推荐系统在网上无处不在,相当标准。亚马逊、网飞和许多这样的公司都在使用推荐系统。我们要构建的这个与 Spotify 或 Youtube 音乐所用的非常相似,但要简单得多。
跟进所需的工具是 Tableau 和 Python3。你可以从这里下载 Tableau。让我先带您浏览一下数据集,稍后我将在数据可视化部分提供 Tableau 的简要介绍。
数据集
百万首歌曲数据集是一百万首当代流行音乐曲目的音频特征和元数据的免费收集。
以下是数据集的链接:
https://static.turi.com/datasets/millionsong/10000.txt
https://static.turi.com/datasets/millionsong/song_data.csv

这是我们需要合并的两个数据集。我们将使用 Python3 连接数据集,并将其导入 Tableau 进行数据可视化。
#importing all the required libraries
import numpy as np
import pandas as pd#importing both the datasets
songmetadata = pd.read_csv(r'Path where the file is located')#one of the file is a text file hence we import it with pd.read_fwf
#fwf stands for fixed width file
othersongdata = pd.read_fwf(r'Path where the file is located')#naming the columns for the othersongdata
othersongdata.columns = ['user_id','song_id','listen_count’]#merging both the datasets and removing duplicates
song_df = pd.merge(othersongdata, songmetadata.drop_duplicates(['song_id']), on="song_id", how="left")#writing the file in .csv to visualize in Tableau
song_df.to_csv(r'Path where you want to store the exported CSV file\File Name.csv', index = False)
组合数据集后,我们得到的是百万首歌曲数据集。该数据集有超过一百万个观察值。数据集由七个变量组成。
**Song_id** = Object
#Unique ID for every song in the dataset, in total there are 1000 songs in the dataset
**User_id** = Object #Unique ID for every user
**Listen_count** = int
#Number of times a song was listened by an user
**Artist_name** = Str
#Name of Artist **Title** = Str
#Title of each song
**Year** = int
#Categorical variable with lot of zero values
**Release** = Str
#Album to which the songs belong to
数据可视化
视觉化给你你不知道的问题的答案—本·施奈德曼
将数据可视化、理解数据并找到见解总是一个很好的实践。我使用 Tableau 是因为它很快,并且提供了大量可视化数据集的选项。Tableau 极大地改进了我的工作流程,而且,我提到过它对学生是免费的吗?
什么是树形图?
我不想撒谎,我喜欢树状图。我在这个项目中广泛使用它们来显示数据。它们很漂亮,可定制,需要关注。
维基百科已经用一种比我更容易理解的格式解释了它,请看下面:
树形图将分层(树形结构)数据显示为一组嵌套的矩形。树的每个分支都有一个矩形,然后用代表子分支的更小的矩形平铺。叶节点的矩形面积与数据的指定维度成比例。【1】通常叶子节点是有颜色的,以显示数据的一个单独的维度。—维基百科
(舞台上由人扮的)静态画面
在写这篇文章的时候,我在想,怎样才能最好地解释“如何在 Tableau 中创建树形图?”。而且我也不想走截图路线。我能做什么?所以我做了一个简单易懂的视频。
要将数据放入 Tableau,需要将。csv 到 excel 工作簿。您可以使用 python 中的以下命令轻松实现:
song_df.to_excel("millionsong.xlsx")
有时转换需要大量的时间,所以我在这里提供了一个可以下载的 excel 工作簿。
绝不是,这是一个全面的 Tableau 指南,它只是一个概述,让你熟悉 Tableau 如何工作以及如何制作树形图。学习 Tableau,查看免费培训,Tableau 官方网站提供这里。

第一个树形图表示数据集中 Year 变量相对于 Listen_count 的比例。该图显示数据集中有许多零。因为我们在创建音乐推荐系统时不打算使用 Year 变量,所以我们不打算删除这些观察值。

第二个树形图表示相对于数据集中的总数 Listen_count 的艺术家。酷玩乐队以 36,406 的点击率成为数据集中最受欢迎的歌手,其次是莱昂国王 T21,点击率为 32,552。
商业问题
太多的选择会让用户不知所措。如果提供的选项太多,用户可能什么都不会买。像 Spotify 这样的流媒体服务有大量的目录。识别用户可能喜欢的曲目并推荐他们可能喜欢的产品对他们的业务至关重要。

我们将创建两个播放列表,一个是受欢迎的播放列表,第二个是识别与用户已经喜欢的歌曲相似的歌曲,从而为他们提供个性化的推荐。
推荐系统

基于内容的推荐系统
CBRS 根据项目的特点和其他项目要素之间的相似性推荐项目。假设用户已经看过喜剧类型的电影,CBRS 将推荐也属于喜剧类型的电影。
协同过滤推荐系统
用户的偏好和态度被认为是创造 CFRS。CFRS 推荐与用户已经选择的项目相似的项目。我们将使用皮尔逊相关来计算相似轨迹之间的关系。

为什么我们不用联想而不用关联?
关联只描述了两个变量之间的关系,而相关不仅描述了关系,还描述了强度。因此,当我们创建一个协同过滤推荐系统时,我们使用相关性。

让我们深入研究代码!
我们将首先创建流行播放列表。我们需要的只是一些数据争论。我尝试在评论中解释代码。尽管如此,如果你有问题,你可以在下面评论。

现在我们将制作 CFRS 并创建个性化播放列表。我使用的观察是,推荐系统的结果在下面给出。


如果你还和我在一起,谢谢。有人抽出时间来看我的作品对我来说意义重大。不要害羞,因为我就是。请在我的 LinkedIn 上与我联系,说‘你好!’,这将使我的一天。
用 Python 创建 NetCDF 文件
一旦你打破了学习曲线,一个强大的数据格式
网格化的空间数据通常存储在 NetCDF 文件中。对于气候数据来说尤其如此。NetCDF 文件通过支持多个变量和详细的元数据,提供了比一些传统栅格格式更大的灵活性和透明度。由于元数据和文件结构的原因,NetCDF 文件比传统的栅格格式更难访问。本文介绍了创建 NetCDF 文件和用 Python 编写数据值的基础知识。我之前写过关于用 Python 从 NetCDF 文件中访问元数据和变量的文章。
创建 NetCDF 数据集
导入netCDF4和numpy模块。然后定义一个扩展名为.nc或.nc4的文件名。调用Dataset,用'w'指定写模式,创建 NetCDF 文件。NetCDF 文件未建立,可以写入。完成后,一定要在数据集上调用close()。
添加维度
NetCDF 文件通常包含三个维度:时间、宽度(x 或经度)和高度(y 或纬度)。宽度和高度尺寸总是固定的。时间维度是动态的(可以增长),允许将时间步长添加到文件中。在 NetCDF 中,动态的或不断增长的维度被称为“无限的”。
可以添加无限的尺寸,并由None指定。我们将对时间变量使用无限的维度,这样它就可以增长。换句话说,我们可以继续向文件添加时间步长。此外,创建纬度和经度维度。lat和lon定义了我们文件的地理范围和维度。这里我们只是创建了一个大小为 10 的维度。这意味着生成的网格只有 10 行和 10 列。lat和lon的大小或地理距离被指定为变量。其实每个维度都会有对应的变量。
添加 NetCDF 变量
变量包含文件的实际数据。它们还定义了数据所引用的网格。这个文件将包含四个变量。纬度和经度定义了网格值和数据位置。times定义数据文件中的图层。value包含实际数据。要创建变量,指定变量名、数据类型和形状。通过引用维度名称,形状被定义为元组。还指定了附加元数据。这里我们将value的单位定义为Unknown。
分配纬度和经度值
用网格单元创建一个简单的网格,用numpy.arange测量 1 度乘 1 度。将 y 值分配给lats,将 x 值分配给lons。现在我们只需要分配与我们创建的网格尺寸相匹配的数据值。
分配 NetCDF 数据值
将两个时间步长的数据添加到我们创建的值变量中。每个时间步长由一个 2D 数数组表示。每个数组的大小必须与lat和lon尺寸相匹配。用numpy.random创建一个从 0 到 100 的随机数数组。该数组包含第一个时间步长的数据。
接下来,创建一个数组,数组中的值从 0.5 线性增加到 5.0。要做到这一点,用numpy.linspace创建两个 1D 数组,并在相反的轴上将它们加在一起。下面的代码展示了这是如何做到的。创建数组并将其分配给value后,关闭ds。您的 NetCDF 现在已保存并准备就绪。在 QGIS 中打开文件进行可视化,或在 Python 中绘制数组。结果的图像如下所示。

带有随机值的 NetCDF(由作者创建)

带有线性插值的 NetCDF(由作者创建)
结论
一旦您理解了 NetCDF 文件的基本结构,它将是处理空间数据的一种非常有用的方式。在这个例子中,我们创建了一个只有一个数据变量的文件。但是可以将多个变量添加到一个文件中,这可能会减少管理数据所需的文件数量。NetCDF 文件最有用的方面之一是阐明它们包含的数据的文档和元数据。
原载于 2020 年 7 月 13 日https://opensourceoptions.com。
使用 getattribute 创建新功能
继承、包装器、类属性等等!

图片由 josealbafotos 提供
作为一个班级的孩子,很难从父母手中夺回控制权。你可能认为一旦你父母给了你一些功能,你就不能改变它了,但事实并非如此!
我们将考虑一个例子,我们想使用父方法给我们的功能,但是我们想在调用父方法之前或之后做一些事情。如果你从一个定义在不属于你的模块中的类继承,这将特别有用。
背景
为了理解如何实现这一点,我们需要理解 Python 如何调用类方法。
考虑下面的类:
class Person:
def set_name(self,name):
self.name = nameclass Worker(Person):
def set_occupation(self,job):
self.occupation = jobxander = Worker()
所以xander是Worker的一个实例。当我们运行xander.set_name("Xander")时,会发生两件事。
- 班级在
set_name上呼叫__getattribute__ - 然后用参数
"Xander"在xander.set_name上调用__call__
我们想改变父类中一个函数的行为,但是我们没有访问它的权限(可能是因为它属于一个不同的模块)。
我们对__call__没有任何控制权,因为该函数归父函数所有。然而,我们确实可以控制我们自己的__getattribute__,所以让我们改为修改它。
功能包装
因此,要添加新功能,我们需要采用原始方法,在之前或之后添加新功能,并将其包装在新函数中。然后,我们中断__getattribute__的正常行为,注入新的包装器。
让我们看一个基本的例子,我们想在函数运行之前和之后添加print语句。
def print_wrapper(func):
def new_func(*args,**kwargs):
print(f"Running: {func.__name__}")
out = func(*args,**kwargs)
print(f"Finished: {func.__name__}")
return out return new_func
为了获得更多令人兴奋的例子,也为了更全面地理解装饰者,我在这里写下了它们:
[## 用 Python decorators 提升你的代码
日志记录、类型检查、异常处理等等!
towardsdatascience.com](/level-up-your-code-with-python-decorators-c1966d78607)
现在我们需要编写新的__getattribute__函数:
def __getattribute__(self, attr):
attribute = super(Parent, self).__getattribute__(attr)
if callable(attribute):
return print_wrapper(attribute)
else:
return attribute
检查属性是否为callable就是检查被选择的属性是否可以用参数调用,因此应用包装器是有意义的。如果属性只是一个属性,而不是一个方法,那么行为将不会改变。
综上所述,我们上面的基本示例应该是这样的:
class Person:
def set_name(self,name):
self._name = namedef print_wrapper(func):
def new_func(*args,**kwargs):
print(f"Running: {func.__name__}")
out = func(*args,**kwargs)
print(f"Finished: {func.__name__}")
return out
return new_funcclass Worker(Person):
def __getattribute__(self, attr):
attribute = Person.__getattribute__(self,attr)
if callable(attribute):
return print_wrapper(attribute)
else:
return attribute
def set_occupation(self,job):
self._job = job
当我们尝试使用它时,我们会得到:
>>> xander = Worker()
>>> xander.set_name("Xander")
Running: set_name
Finished: set_name
>>> xander.set_occupation("Butcher")
Running: set_occupation
Finished: set_occupation
>>> print(xander.__dict__)
{'_name': 'Xander', '_job': 'Butcher'}
警告的话
使用这些类型的函数,弄乱__getattribute__应该小心,每个属性都会调用它,所以添加计算密集型功能会大大降低程序的速度。摆弄像__getattribute__这样的函数也很容易导致递归错误和内核崩溃,因为类会一次又一次地调用自己。
这种递归的一个例子是,如果你使用__getattribute__调用__dict__,因为__dict__本身调用__getattribute__,所以循环继续…
我们学到了什么?
使用 Python 对象的双下划线方法可以让您节省大量时间和精力。实现同样目标的另一种方法是重新实现每个函数和装饰器。对于上面的例子来说,这可能不会太糟糕,但是想象一下,如果你的父类是像 Pandas 数据框或 NumPy 数组这样的东西,那么这将成为一项非常艰巨的任务。
使用 MLflow 项目和 Docker 创建可重用的 ML 模块
因为你永远不会只训练你的模型一次。
让我们面对现实吧,将机器学习模型投入生产并不容易。从从不同来源收集数据到调整超参数和评估模型性能,从沙盒到生产有如此多的不同步骤,如果我们不小心,可能会分散在许多相互依赖的笔记本或脚本中,所有这些都必须以正确的顺序运行才能重新创建模型。更糟糕的是,当我们迭代和评估模型的新版本时,很容易忽略记录超参数的每个组合和每个结果度量,因此我们经常会忘记在迭代模型构建过程中吸取的教训。
还记得我们用来制作模型第一版的笔记本吗?好吧,当我们完成第二版的时候,那些笔记本已经被调整和改变了太多,如果我们需要的话,我们已经没有希望重新创建第一版了。
在本文中,我将展示如何使用 MLflow 和 Docker 来创建模块化的、可重用的 ML 项目,并允许您轻松地重新创建旧版本的模型和调整参数来构建和评估新的模型。
什么是 MLflow?
MLflow 是一套开源工具,帮助管理 ML 模型开发生命周期,从早期的实验和发现,一直到在中央存储库中注册模型并将其部署为 REST 端点以执行实时推理。在本文中,我们不会涉及模型注册中心或模型部署工具。我们的重点将是 MLflow 跟踪,它允许我们在快速迭代模型的不同版本时评估和记录模型结果,以及 MLflow 项目,我们将使用它将我们的模型开发工作流打包到一个可重用的参数化模块中。
我们将建造什么
在本文中,我们将使用 TensorFlow 和 CelebA 数据集来构建一个基本的卷积神经网络,以预测给定图像的主体是否在微笑。我们将创建一个 Docker 映像,它将作为我们的训练环境,并将包含训练模型所需的所有依赖项。接下来,我们将模型训练代码打包为 MLflow 项目,最后,我们将创建一个简单的驱动程序,该程序将使用不同的超参数值异步启动项目的多次运行。
本地设置
为了跟进,您需要在本地安装 Python 3 、 Docker 和 MLflow。您可以使用pip安装 MLflow
pip install mlflow
构建模型
由于我们的重点是 MLflow,所以我不会详细介绍实际的模型,但是我会简要地介绍一些代码示例,并在本文的最后提供一个工作端到端项目的链接。
首先要做的是加载 CelebA 数据集。我们将使用 TensorFlow 数据集来完成这项工作。
从 tfds 加载的数据集不包含显式目标值。每个记录只是一个图像和关于该图像的一组属性(例如,图像中的人是否在微笑、是否戴着帽子、是否有胡子等等)。),所以使用data_generator()函数以一种可以传递到模型中的方式格式化数据。该函数返回一个生成器,该生成器将每条记录生成为以下格式的元组:
(image, 1 if subject is smiling else 0)
我们将通过使用tf.data.from_generator并传入data_generator()函数来为模型创建训练和验证数据集。
接下来,我们将使用训练和验证数据集来构建和训练 CNN。
创建项目环境
MLflow 项目允许您以三种不同的方式定义环境: Conda、Docker 容器或本地系统。我们将在项目环境中使用 Docker 容器。
下面是我们简单项目环境的 docker 文件:
requirements.txt 文件包含运行项目所需的包: mlflow 、 tensorflow 和 tensorflow-datasets。和 load_data.py 脚本只是从 TensorFlow 加载 CelebA 数据集,并将结果存储在 /app/data 目录中。
注意:在现实世界的场景中,您可能不会将培训/验证数据与项目环境一起存储。相反,您的环境将只包括访问数据所需的配置和库,无论数据存储在哪里(例如,本地数据库或云存储帐户)。我这样做只是为了避免每次项目运行时从 TensorFlow 下载数据集。
打包培训代码
我们现在将前面的模型训练代码打包到一个 MLflow 项目中。MLflow 项目只是一个带有 MLproject 文件的目录,该文件定义了项目的一些内容:
- 项目将运行的环境。对我们来说,这是我们刚刚创建的 Docker 图像。
- 项目入口点。这将是构建和训练模型的 python 脚本。
- 可以传递到项目中的参数。我们将在下面定义其中的一些。
第一步是创建一个 MLproject 文件。正是在这个文件中,我们引用了将被用作项目环境的 Docker 图像。我们还将定义可以传递到项目中的任何参数。
如您所见,我们的项目将使用 gnovack/celebs-cnn 图像作为项目环境(这是上一节中创建的 Docker 图像),并将接受许多参数:批处理大小、时期数、卷积层数、训练和验证样本数,以及一个布尔值,该值指示是否在训练期间对输入图像执行一些随机转换。
接下来,我们将修改模型训练代码,以使用传入的参数,并使用 MLflow 跟踪来记录训练进度。我们将很快讨论 MLflow 跟踪,但现在只知道它由一个跟踪服务器和一个 GUI 组成,跟踪服务器在模型训练运行(MLflow 称之为实验运行)期间跟踪参数和指标,GUI 允许我们查看所有运行并可视化每次运行的性能指标。
我们可以像使用任何命令行参数一样使用argparse来访问项目输入参数。
然后我们可以使用这些参数来动态构建 CNN。我们还将在 MLflow 运行中包装模型训练,使用mlflow.start_run()告诉 MLflow 将我们的模型训练作为 MLflow 实验运行进行跟踪。
关于上述代码的几点注意事项:
mlflow.tensorflow.autolog()支持自动记录 TensorFlow 的参数、指标和模型。MLflow 支持几种机器学习框架的自动日志记录。完整列表见此:https://ml flow . org/docs/latest/tracking . html #自动记录。- 在训练期间随机旋转图像以帮助防止过度拟合的
RandomFlip层,现在根据randomize-images参数的值有条件地添加到模型中。 - 模型中卷积层的数量现在取决于参数
convolutions的值。 - 自定义回调已添加到
model.fit调用中。MLFlowCallback是一个简单的 Keras 回调类,它在每个训练期之后使用mlflow.log_metrics()向 MLflow 跟踪服务器发送模型性能指标
编写驱动程序
定义了 Docker 环境并创建了 MLflow 项目后,我们现在可以编写一个驱动程序来异步执行该项目的一些运行,从而允许我们评估超参数和神经网络架构的不同组合。
在运行项目之前,我们需要启动 MLflow 跟踪服务器。对于本例,我们将只使用您的本地计算机作为跟踪服务器,但是在您与一个工程师和/或数据科学家团队合作的环境中,您可能希望建立一个共享的跟踪服务器,该服务器始终运行,供所有团队成员共享。一些云服务,如 Databricks 和 Azure 机器学习,甚至内置了 MLflow 跟踪服务器。
要运行本地跟踪服务器并打开 MLflow GUI,请运行以下命令:
mlflow ui
我们将使用链接到 Github 中 MLflow 项目的mlflow.projects.run()方法、https://github.com/gnovack/celeb-cnn-project来运行项目(您也可以使用包含 MLflow 项目的本地目录的相对文件路径)。驱动程序脚本使用不同的参数异步运行项目三次。
我们指定synchronous=False,这样我们可以并行执行所有三次运行,而backend='local'表示项目将在您的本地机器上执行。MLflow 还支持在 Databricks 或 Kubernetes 集群上执行项目。
执行驱动程序后,进入 http://localhost:5000/ 查看 MLflow 跟踪 UI 中的三个活动运行。

MLflow 运行。(图片由作者提供)
通过深入每次运行,您可以查看模型性能指标,由于我们创建了MLFlowCallback,这些指标会在每个训练时期后更新,使我们能够在模型仍在训练时绘制这些指标。

MLflow 跟踪指标。(图片作者)
正如您从准确性数字中看到的,我们的模型在使用少量数据进行几次训练后不会赢得任何奖项,但您可以开始看到不同模型的性能趋势(例如,未使用卷积层的顶级模型似乎过度拟合数据,因为训练准确性稳步上升,而验证准确性保持相当稳定)。一旦每次运行完成,它将输出已训练的模型对象作为可以从跟踪服务器下载的工件,这意味着,通过 MLflow 跟踪,我们不仅可以访问历史训练运行的参数和指标,还可以访问已训练的模型。
当处理更复杂的模型和更大的训练数据集时,训练过程很容易需要几个小时或几天才能完成,因此能够实时查看这些指标使我们能够确定哪些参数组合可能会或可能不会产生生产质量的模型,并使我们有机会在看到性能指标中的过度拟合等趋势时停止运行。
结论
在本文中,我们已经看到了如何使用 MLflow 项目将机器学习模型的开发和训练打包到一个封装的可重用模块中,允许我们并行训练模型的几个版本,并在训练过程中实时比较它们的性能。MLflow 还让我们能够跟踪与每个历史项目运行相关的参数、指标和模型,这意味着如果需要的话,我们可以很容易地复制任何以前版本的模型。还值得注意的是,虽然我们在本文中只使用了 TensorFlow,但是 MLflow 跟踪和 MLflow 项目可以与所有主要的 ML 框架一起工作。
感谢阅读!我将留下包含本文中描述的端到端项目的存储库的链接,以及我在从事这项工作时参考的一些有用的文档。如有任何问题或意见,请随时联系我们。
Github 仓库
- 包含构建 Docker 环境所需代码的存储库:https://github.com/gnovack/celeb-cnn-base-image。
- 生成的图像存储在 Docker Hub:【https://hub.docker.com/repository/docker/gnovack/celebs-cnn
- MLflow 项目存储库包含【https://github.com/gnovack/celeb-cnn-project】ml Project 文件和张量流模型代码ml Project
- 执行 MLflow 项目并行运行的驱动程序:https://github.com/gnovack/celeb-cnn-driver
参考
- https://mlflow.org/docs/latest/projects.html#
- https://ml flow . org/docs/latest/tracking . html # tensor flow-and-keras-experimental
- https://www.tensorflow.org/datasets/catalog/celeb_a
- https://www.tensorflow.org/api_docs/python/tf/data/Dataset?hl=en
将 TensorFlow 2 深度学习分类器用作 REST API(有 GPU 支持),第一部分
端到端 TensorFlow REST API
在这一系列文章中,我将一步一步地解释如何使用 Flask 创建和服务一个图像分类器作为 REST API!🚀稍后我们将把它归档🐳!

在 Jupyter 笔记本上编写深度学习图像分类器很棒,如果你部署你的模型,让你的客户有可能使用它,那就更棒了!
这一系列文章将帮助您从笔记本转向数据科学技术的真实使用案例!我们将深度学习分类器从零到生产🚀!
免责声明:你应该有CNN-卷积神经网络 的先验知识和经验。
我们将用来训练我们的卷积神经网络分类器的数据集是 CIFAR-10 ( 暂时不要下载)。CIFAR-10 数据集包括 10 类 60000 幅 32×32 彩色图像,每类 6000 幅图像。有 50000 个训练图像和 10000 个测试图像。
以下是数据集中的类,以及每个类中的 10 幅随机图像:

准备好了吗?我们走吧!
1 —创建我们的项目结构
受 cookiecutter-data-science 开源模板的启发太多,下面是我最喜欢的数据科学项目结构:

我最喜欢的数据科学项目结构
- 在数据/raw 中,我复制我的原始数据并在数据/中处理;我保留预处理过的数据。
- 在 deploy 文件夹中,您可以找到 Dockerfile 和 requirements.txt 或 environment.yml (仅保存生产库)
- 在 models 的文件夹中,我存储了保存的模型。
- 在笔记本文件夹中,我有我的笔记本(。ipynb 文件)
- 在参考文件夹中,我放入了元数据和我在项目中使用的资源的所有参考(pdf,笔记…等等)
- 在报告文件夹中,我放了所有的图表和报告(png、pdf、幻灯片),其中包含与我的团队分享的见解
- 在 src 文件夹中,我的 Python 脚本按以下方式分组:src/API文件夹用于创建 REST API 的脚本,src/ data 文件夹包含用于处理数据的脚本,src/ dags 文件夹包含我的 Airflow DAG s,src/ 【T25
- **测试文件夹包含用于测试我的应用程序的 python 脚本
- 我在那里配置我的 Python 日志记录器
- db_config.json 只是一个 json 文件,包含一些数据库访问配置
为了简化起见,让我们稍微简化一下我们的项目结构,只创建(暂时保留所有内容为空):
- 数据 文件夹
- 部署 文件夹
- 型号 文件夹
- 笔记本 文件夹
- src 文件夹内的 src/model 和 src/api 子文件夹
- environment . yml文件
- logging.yml 文件
就像我一样,你最终会得到这些文件夹

项目结构
太好了!您已经准备好了一个清晰的项目结构!让我们建立我们的工作环境!
2 —开发设置
按照以下步骤创建一个在 environment.yml 文件中定义的虚拟 Python 3 工作环境,并配置您的 GPU:
- 2.1 — 安装 Miniconda 3 (或 Anaconda 3 )
- 2.2 — 确保 conda 在您的路径上(否则将 bin 文件添加到您的 $PATH ):
*$ which conda~/anaconda3/bin/conda*
- 2.3 — 如果你有 CUDA 计算能力 3.5 或更高的 NVIDIA GPU 卡,请按照以下步骤启用 TensorFlow GPU 支持https://www . tensor flow . org/install/GPU # software _ requirements(暂时不要 pip 安装 tensorflow !首先配置 CUDA,我们将在下一步安装 tf2(2.4)
- 2.4 — 我们现在调用我们的虚拟环境tf2-image-classifier-API,然后在environment . yml文件中指定所需的包(复制粘贴以下代码): tensorflow-gpu 、 numpy 、 seaborn 、 jupyter 用于创建图像分类器烧瓶和女侍用于休息 API 创建。tqdm 用于获得令人愉快的进度条,最后,opencv-python 用于图像预处理!
environment.yml 文件
- 2.5 — 现在转到项目根目录,创建一个虚拟环境:
*$ conda env create -f environment.yml*
- 2.6 — 激活虚拟环境
*conda activate tf2-image-classifier-api*
您现在应该已经激活了您的虚拟环境!

奖金(仅供参考,现在不需要):
彻底清除环境
*conda env remove — name tf2-image-classifier-api*
将环境包更新到最新的兼容版本
*conda env update -f environment.yml*
- 2.7 — 从此处 下载 CIFAR-10 数据集,但为 png 格式
- 2.8 — 将下载的 cifar.tgz 文件复制到data/raw文件夹中并解压到那里(你应该会得到 train 文件夹、 test 文件夹和 labels.txt 文件)

解压 cifar.tgz 文件并将其移动到data/raw后
太好了!现在,您的环境和数据集已经为我们的图像分类器训练和预测做好了准备!
3-加载库和数据集
首先在项目的根中运行 jupyter notebook 命令:
**$ jupyter notebook**
现在导航到http://localhost:8888/tree/notebooks
创建新笔记本

创建新的 Jupyter 笔记本
并遵循以下步骤:
3.1 —导入 tensorflow 并检查 GPU 支持
第一次,加载所需的 cuDNN libs(帮助 TensorFlow 发现您的 GPU 设备)需要几分钟时间。如果一切正常,你会得到与我相似的结果(除了我有一个 GTX 960M/CUDA v10.2)。

导入 tf2 并检查 GPU 支持
3.2-导入其他必需的库
3.3-加载数据集
但是之前我们需要定义两个方法;read _ image&load _ dataset
-
使用 OpenCV 读取图像
-
通过可视化一些图像来测试该方法
结果

从训练集中可视化的随机图像
-
加载数据集并以 numpy 数组的形式返回图像和目标
-
现在我们已经准备好加载我们的训练&测试数据集!
-
检查您的训练数据和测试数据形状
如果一切正常,你会得到和我相似的结果。

验证数据集形状
太好了!现在我们已经加载了库,数据集也准备好了!让我们创建我们的 CNN 架构!
4 —创建图像分类深度学习模型
我们不需要重新发明轮子,我们将使用这个 CNN 架构但是在 TensorFlow 2.2 中!

我们的 CNN 模型架构— 图片来源
整个模型总共包括 16 层:
- 批量标准化
- 与 64 个大小为(3×3)的不同滤波器进行卷积
- 最大池容量为 2
- ReLU 激活功能
- 批量标准化
4.与 128 个大小为(3×3)的不同滤波器进行卷积
5.最大池容量为 2
- ReLU 激活功能
- 批量标准化
6.与 256 个大小为(3×3)的不同滤波器进行卷积
7.最大池容量为 2
- ReLU 激活功能
- 批量标准化
8.与 512 个大小为(3×3)的不同滤波器进行卷积
9.最大池容量为 2
- ReLU 激活功能
- 批量标准化
10.展平最后卷积运算的三维输出。
11.具有 128 个单元的全连接层
- 拒绝传统社会的人
- 批量标准化
12.具有 256 个单元的全连接层
- 拒绝传统社会的人
- 批量标准化
13.具有 512 个单元的全连接层
- 拒绝传统社会的人
- 批量标准化
14.具有 1024 个单元的全连接层
- 拒绝传统社会的人
- 批量标准化
15.具有 10 个单元的全连接层(图像类的数量)
16.Softmax
4.1 —创建卷积块
定义一种创建卷积块的方法(使用最大池和批量标准化)
4.2 —创建密集块
定义一种创建密集块的方法(带丢弃和批量标准化)
4.3 —使用 TF 2 Keras 创建 CNN 模型
酷!现在我们已经准备好创建 CNN 的助手函数了!
这个函数帮助我们创建一个 CNN Keras 模型准备编译!
现在我们可以定义我们的训练超参数:
训练超参数,你应该调整以获得更好的结果!
现在可以实例化我们的模型了。还有,我们来看看它的总结。
应该能打印出来
**Model: "keras_image_classification_model"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
inputs (InputLayer) [(None, 32, 32, 3)] 0
_________________________________________________________________
batch_normalization_15 (Batc (None, 32, 32, 3) 12
_________________________________________________________________
conv_1_features (Conv2D) (None, 32, 32, 64) 1792
_________________________________________________________________
max_pooling2d_8 (MaxPooling2 (None, 16, 16, 64) 0
_________________________________________________________________
batch_normalization_16 (Batc (None, 16, 16, 64) 256
_________________________________________________________________
conv_2_features (Conv2D) (None, 16, 16, 128) 73856
_________________________________________________________________
max_pooling2d_9 (MaxPooling2 (None, 8, 8, 128) 0
_________________________________________________________________
batch_normalization_17 (Batc (None, 8, 8, 128) 512
_________________________________________________________________
conv_3_features (Conv2D) (None, 8, 8, 256) 819456
_________________________________________________________________
max_pooling2d_10 (MaxPooling (None, 4, 4, 256) 0
_________________________________________________________________
batch_normalization_18 (Batc (None, 4, 4, 256) 1024
_________________________________________________________________
conv_4_features (Conv2D) (None, 4, 4, 512) 3277312
_________________________________________________________________
max_pooling2d_11 (MaxPooling (None, 2, 2, 512) 0
_________________________________________________________________
batch_normalization_19 (Batc (None, 2, 2, 512) 2048
_________________________________________________________________
flatten_2 (Flatten) (None, 2048) 0
_________________________________________________________________
dense_1_features (Dense) (None, 128) 262272
_________________________________________________________________
dropout_4 (Dropout) (None, 128) 0
_________________________________________________________________
batch_normalization_20 (Batc (None, 128) 512
_________________________________________________________________
dense_2_features (Dense) (None, 256) 33024
_________________________________________________________________
dropout_5 (Dropout) (None, 256) 0
_________________________________________________________________
batch_normalization_21 (Batc (None, 256) 1024
_________________________________________________________________
dense_3_features (Dense) (None, 512) 131584
_________________________________________________________________
dropout_6 (Dropout) (None, 512) 0
_________________________________________________________________
batch_normalization_22 (Batc (None, 512) 2048
_________________________________________________________________
dense_4_features (Dense) (None, 1024) 525312
_________________________________________________________________
dropout_7 (Dropout) (None, 1024) 0
_________________________________________________________________
batch_normalization_23 (Batc (None, 1024) 4096
_________________________________________________________________
dense_1 (Dense) (None, 10) 10250
_________________________________________________________________
softmax (Softmax) (None, 10) 0
=================================================================
Total params: 5,146,390
Trainable params: 5,140,624
Non-trainable params: 5,766**
精彩!5140624 个参数来训练!
4.4 —编译我们的 CNN Keras 模型
为了训练我们的模型,我们将使用 RMSprop 作为优化器& 作为损失函数。为什么稀疏分类交叉熵而不仅仅是分类交叉熵?好问题!下面是为什么是!
现在我们可以编译我们的模型了!
使用 RMSProp 作为优化器和 CategoricalCrossentropy 作为损失函数来编译 CNN 模型
4.5 —训练我们的 CNN Keras 模型
一切都准备好训练我们的模型了。然而,让我们定义三个回调:
CNN 培训!
如果一切正常,你的模特应该开始训练了!你应该得到和我相似的结果。

我的 CNN 培训!
太好了!你的 GPU 现在正在燃烧🔥!让它训练你的模型,我们将在训练结束后回来!(这里是我的 GPU 努力工作的截图)

我训练 Keras CNN 时的 GPU
如果你想像汤姆那样,就拍快照吧!

4.5 —测试我们的模型
酷!我们的分类器已经完成训练!是时候评估一下了,对吧?它是如何处理测试图像的?我们可以通过使用下面的命令启动笔记本中的 tensorboard 界面来检查这一点。
*%tensorboard --logdir logs*
此命令应启动 tensorboard,并显示精度和损耗图,用于训练和验证:

张量板
但是等等,对于一个分类器来说,准确度不是一个好的评估指标!让我们检查每一个类的精确度、召回率和 f1 分数!我们能做到这一点要感谢 scikit-learn 的 分类 _ 报告 方法:
分类报告
这些是我的结果:
*precision recall f1-score support airplane 0.84 0.86 0.85 1000
automobile 0.92 0.92 0.92 1000
bird 0.76 0.72 0.74 1000
cat 0.63 0.67 0.65 1000
deer 0.80 0.81 0.80 1000
dog 0.74 0.72 0.73 1000
frog 0.86 0.86 0.86 1000
horse 0.87 0.86 0.86 1000
ship 0.91 0.90 0.91 1000
truck 0.88 0.89 0.88 1000 accuracy 0.82 10000
macro avg 0.82 0.82 0.82 10000
weighted avg 0.82 0.82 0.82 10000*
第一次尝试不错,对吧? 0.82 精度& 0.82 召回!我们可以调整超参数并重新训练模型以获得更好的结果!
用你的结果来回应这个故事!我很乐意检查它们!😊
让我们做一个推理测试。给出测试集中的图像,让我们发现我们的模型看到了什么!
结果

5-导出模型
不错!我们的模型在测试数据上表现很好,现在我们可以将它导出到磁盘。我们保存的模型用于进行推理,并将作为 REST API 公开!
最后,让我们通过加载来检查保存的模型是否工作正常!
精彩!精彩!精彩!您已经成功创建、训练(在 GPU 上)、测试并保存了一个 TensorFlow 2 深度学习图像分类器!
现在我们准备将它公开为一个带有 Flask 和 waste 的 REST API,稍后将所有东西 Dockerize!
准备好了吗?走吧。
6 —开发一个 REST API
但是等等,这对于一个中等的故事来说已经太多了😔!敬请关注第二部分!🚀
所有的源代码都在我的 GitHub 上👇我会继续推动一切!
* [## Hz iton/tensor flow-2-深度学习-图像-分类器-REST-API-Docker-GPU
媒体故事的源代码🚀创建和服务 TensorFlow 2 深度学习图像分类器作为 REST API 和…
github.com](https://github.com/hzitoun/tensorFlow-2-Deep-Learning-Image-Classifier-REST-API-Docker-GPU)*
太好了!感谢您的阅读!我渴望在第二部里见到你(即将上映)!
我希望我已经帮助你使用 TensorFlow 2.2 创建了一个深度学习图像分类器。在第二部分中,我们将把保存的模型公开为 REST API,稍后我们将对所有内容进行 dockerize!
如果你喜欢这个故事,请考虑分享。那会有很大帮助。
最后,我每天在 LinkedIn 上分享机器学习👉https://www.linkedin.com/in/hamed-zitoun/与我联系😊
用 Python 创建简单的光学字符识别(OCR)
宇宙魔方光学字符识别初学者指南

当为文本挖掘过程收集数据或查找其他参考资料时,我们经常会找到图像形式的源。例如,如果我们要分析 pdf 格式的单词,文件会包含文本图像。这无疑使数据处理变得困难。解决这个问题的一个方法是我们可以使用光学字符识别(OCR)。
OCR 是一种识别图像中文本的技术,例如扫描文档和照片。常用的 OCR 工具之一是 魔方 。宇宙魔方是各种操作系统的光学字符识别引擎。它最初是由惠普公司作为专有软件开发的。后来谷歌接管了开发。
目前,宇宙魔方在 Windows、macOS 和 Linux 平台上运行良好。宇宙魔方支持 Unicode (UTF-8)并支持 100 多种语言。在本文中,我们将从镶嵌 OCR 安装过程开始,并测试图像中文本的提取。
第一步是安装宇宙魔方。为了使用宇宙魔方库,我们首先需要在我们的系统上安装它。如果您正在使用 Ubuntu,您可以简单地使用 apt-get 来安装宇宙魔方光学字符识别:
sudo apt-get install tesseract-ocr
对于 macOS 用户,我们将使用自制软件来安装宇宙魔方。
brew install tesseract
对于 Windows,请参见 魔方文档 。让我们从安装侏儒怪开始。
$ pip install pytesseract
安装完成后,让我们继续用 python 应用宇宙魔方。首先,我们导入依赖项。
from PIL import Image
import pytesseract
import numpy as np
我将使用一个简单的图像来测试魔方的用法。我将使用下面的图像。

示例图像
让我们加载此图像并将其转换为文本。
filename = 'image_01.png'
img1 = np.array(Image.open(filename))
text = pytesseract.image_to_string(img1)
现在,让我们看看结果。
print(text)
这就是结果。

从宇宙魔方获得的结果对于简单的图像来说已经足够好了。因为在现实世界中很难找到真正简单的图像,所以我将添加噪声来观察宇宙魔方的性能。我将使用下面的图像。

有噪声的样本图像
然后,我们将执行与之前相同的过程。
filename = 'image_02.png'
img2 = np.array(Image.open(filename))
text = pytesseract.image_to_string(img2)
print(text)
这就是结果。

结果是……没什么。这意味着宇宙魔方无法读取有噪声的图像中的单词。
然后我们尝试使用一点图像处理来消除图像中的噪声。在这里,我将使用开放简历库。在这个实验中,我使用归一化,阈值和图像模糊。
import numpy as np
import cv2norm_img = np.zeros((img.shape[0], img.shape[1]))
img = cv2.normalize(img, norm_img, 0, 255, cv2.NORM_MINMAX)
img = cv2.threshold(img, 100, 255, cv2.THRESH_BINARY)[1]
img = cv2.GaussianBlur(img, (1, 1), 0)
那么结果就会是这样。

预处理图像
图像足够干净,然后我们将再次尝试与以前相同的过程。这就是结果。

从上图可以看出,结果与我们所期望的一致。
[## 在 Tesseract OCR 中创建文本定位和检测的简单方法
如何利用 Tesseract 来检测、定位和 OCR 文本
medium.com](https://medium.com/@fahmisalman/an-easy-way-of-creating-text-localization-and-detection-in-tesseract-ocr-24cc89ed6fbc)
可以得出的结论是,当构建扫描和处理图像的文档处理管道时,tesseract 是最合适的。这最适合高分辨率输入的情况,在这种情况下,前景文本从背景中整齐地分割出来。
创建 TFRecords 数据集并使用它来训练 ML 模型
有益于处理顺序学习模型的人

嗨,极客们,
希望你一切安好。
在这个故事中,你将了解到。什么是 TFRecords?
2。如何将数据保存为 tfrecords 文件?
3。提取 TFRecord 数据。
4。如何使用 tfrecord 中的数据集来训练模型?
PS——如果你只是来拿代码的话。从这里开始享用吧!
什么是 TFRecords?
TFRecord 是一种 Tensorflow 格式,用于存储二进制记录序列。除了顺序数据,TFrecord 还可以用于存储图像和 1D 矢量。在本文中,我们将看到如何存储和读取以下类型的数据:
(i) Integer。(int64,uint8 等。)
(二)花车。
(三)琴弦。
(四)图像。
TFRecord 只能按顺序读写。因此,它通常被用于序列模型,如 RNN,LSTM 等。但这并不意味着我们只能用它来进行连续学习。
如何将数据保存为 tfrecords 文件?
要将任何数据存储到 tfrecords,我们首先需要创建 TensorFlow 示例。这些张量流示例可以使用 tf.train.examples 函数创建。这个函数将创建一个包含一些特性的示例对象。代码如下-
example = tf.train.Example(features = tf.train.Features(feature = { }))
功能中应该有什么?
这些特征包含我们的图像、数据,还包含该数据的文件名。如果有人使用监督算法,图像的相应标签也会出现在特征中。因此,创建特征的典型代码是—
注意- 图像和相应的标签已经以字节格式保存。
一旦我们创建了一个图像的例子,我们需要把它写入一个 trfrecord 文件。这些可以使用 tfrecord writer 来完成。下面代码中的 tfrecord_file_name 是我们要存储图像的 tfrecord 的文件名。TensorFlow 会自动创建这些文件。
writer = tf.python_io.TFRecordWriter(tfrecord_file_name)
writer.write(example.SerializeToString())
存储图像的代码
提取 TFRecord 数据
如果你知道写它们的正确方法,读 tfrecord 文件就简单多了。过程是一样的。首先,我们需要创建一个用于编写 rfrecord 文件的特性字典。然后我们将使用TF . train . tfrecorddataset函数创建一个 dataset 对象。
创建数据集对象后,我们将使用下面给出的代码将该数据集对象映射到我们想要的数据集。
在上面这段代码中,函数 _extract_fn 将数据集映射到我们想要的东西的列表中(文件名、图像、标签、图像形状)。为此,我们首先解析我们在 tfrecords 生成过程中制作的示例。解析之后,我们需要使用 tf.io.decode_raw() 函数将解析后的示例解码成图像。
如何使用 tfrecord 中的数据集来训练模型?
为了使用从 tfrecord 提取的数据来训练模型,我们将在 dataset 对象上创建一个迭代器。
iterator = tf.compat.v1.data.make_initializable_iterator(batch_dataset)
创建这个迭代器后,我们将循环进入这个迭代器,这样我们就可以在从这个迭代器中提取的每个图像上训练模型。函数 extract_image 通过使用 iterator.get_next()对 tfrecord 中出现的每个图像执行此操作。关于这个函数,请参考下面的代码。
希望你现在对 tfrecord 有所了解,以及我们如何利用它们来训练模型。
编码快乐!
使用“virtualenv”创建虚拟环境,并将其添加到 Jupyter 笔记本中
你是机器学习工程师,正在使用 Python 和 Jupyter Notebook 吗?在本文中,您将看到为什么需要虚拟环境,一些现有工具的区别以及如何将虚拟环境添加到 Jupyter Notebook 中。

照片由 Hitesh Choudhary 在 Unsplash 上拍摄
下面是文章大纲:
- 为什么需要虚拟环境?
virtualenv、virtualenvwrapper、penv和venv有什么区别?- 使用
virtualenv创建一个虚拟环境 - 将虚拟环境添加到 Juypter 笔记本
为什么需要虚拟环境?
像其他编程语言一样,Python 有自己下载、存储和解析包(或库)的方式。默认情况下,您机器上的每个 Python 项目都将使用默认的 Python site-packages 目录(该目录与主 Python 安装相关联,表示为 base(root) 环境)。您可以通过以下方式找到答案:
>>> import site
>>> site.getsitepackages()
['/Users/admin/anaconda3/lib/python3.7/site-packages']
想象一个场景,你在做两个机器学习项目,其中一个使用 TensorFlow v1.5,另一个使用 TensorFlow v2。这将是一个真正的问题,因为 Python 不能区分站点包目录中的版本。TensorFlow v1.5 版和 TensorFlow v2 将驻留在同名的同一目录中。由于版本之间没有区别,两个项目将被要求使用相同的版本,这在这种情况下是不可接受的。这就是虚拟环境工具发挥作用的地方。
Python 虚拟环境的主要目的是为 Python 项目创建一个隔离的环境。每个项目都可以有自己的依赖项,不管其他项目有什么依赖项。
此外,当您需要在共享系统上工作并且没有安装软件包的权限时,虚拟环境也很有用,因为您可以在虚拟环境中安装它们。
下面是一些流行的用 Python 创建虚拟环境的库/工具:virtualenv、virtualenvwrapper、pvenv、venv。
如果你对使用conda创建虚拟环境感兴趣,可以看看:
[## 使用“conda”创建虚拟环境,并将其添加到 Jupyter 笔记本中
你正在使用 anaconda 和使用 Jupyter Notebook 和 Python 吗?在这篇文章中,你将看到如何创建虚拟的…
medium.com](https://medium.com/analytics-vidhya/create-virtual-environment-using-conda-and-add-it-to-jupyter-notebook-d319a81dfd1)
【virtualenv,virtualenvwrapper,pvenv,venv 有什么区别?
[**virtualenv**](https://virtualenv.pypa.io/en/stable/#):是创建隔离 Python 环境最流行的库。你可以通过跑pip install virtualenv得到它。它的工作原理是在本地目录中制作 Python 解释器二进制文件的精确副本(python或python3)。通过修改PATH环境变量,在它前面加上一个自定义的 bin 目录,可以激活一个环境。[**virtualenvwrapper**](https://pypi.org/project/virtualenvwrapper/):是virtualenv的一组扩展。它给你像mkvirtualenv、lssitepackages,尤其是workon这样的命令,用于在不同的virtualenv目录之间切换。如果您想要多个virtualenv目录,这个工具非常有用。**pyvenv**:是 Python 3 附带的库,但是在 Python 3.6 中贬值了,因为它有问题。[**venv**](https://docs.python.org/3.6/library/venv.html#module-venv):是 Python 3.3+附带的库。您可以使用python3 -m venv <path_to_new_env>.运行,它的作用与virtualenv相同,此外还可以延长。
virtualenv继续比venv更受欢迎,尤其是因为前者同时支持 Python 2 和 3。对初学者的一般建议是,从学习同时适用于 Python 2 和 3 的virtualenv和pip开始。在各种情况下,一旦你开始需要其他工具,就拿起它们。
使用“virtualenv”创建虚拟环境
安装virtualenv
检查你是否有virtualenv
which virtualenv
如果没有,请在您的终端中输入以下内容进行安装。
pip install virtualenv
创建虚拟环境
要在当前目录中创建虚拟环境,请执行以下操作:
virtualenv <my_env_name>
下面是一个在当前目录“/Users/admin/Code/WorkSpace/python-venv/”下创建虚拟环境“ nlp ”的例子。
⇒ virtualenv **nlp**
Using base prefix '/Users/admin/anaconda3'
New python executable in /Users/admin/Code/WorkSpace/python-venv/**nlp/bin/python**
Installing setuptools, pip, wheel...done.
使用特定版本的 Python 创建一个环境
也可以使用自己选择的 Python 解释器(比如python2.7)。
virtualenv **-p /usr/bin/python2.7** <my_env_name>
从 requirements.txt 文件创建环境
通常情况下,您总是采取以下步骤:
virtualenv <my_env_name>创造新环境source <my_env_name>/bin/activate激活新环境pip install -r requirements.txt在当前环境中安装需求
或者,你可以考虑使用 pipenv ,它结合了pip和virtualenv。
激活虚拟环境
您可以通过运行以下命令来激活虚拟环境:
source <my_env_name>/bin/activate
下面是一个激活“ nlp 的例子:
⇒ pwd
/Users/admin/Code/WorkSpace/python-venv⇒ **source nlp/bin/activate**⇒ which python
/Users/admin/Code/WorkSpace/python-venv/nlp/bin/python
停用虚拟环境
要停用当前环境,您可以键入:
deactivate
检查你所处的环境
您可以通过运行which python或which pip来快速验证您是否在环境中,如果一切顺利,这将返回 python 可执行文件在环境中的路径:
⇒ which python
/Users/admin/Code/WorkSpace/python-venv/nlp/bin/python⇒ which pip
/Users/admin/Code/WorkSpace/python-venv/nlp/bin/pip
移除环境
要删除一个环境,请确保您已将其停用,然后cd进入环境目录并键入
sudo rm -rf <my_env_name>
向 Jupyter 笔记本电脑添加虚拟环境
确保 IPython 内核可用,但是您必须手动添加一个具有不同 Python 版本或虚拟环境的内核。
首先,你需要激活你的虚拟环境。
接下来,安装为 Jupyter 提供 IPython 内核的 ipykernel :
然后,您可以通过键入以下命令将您的虚拟环境添加到 Jupyter:
python -m ipykernel install --user --name=<my_env_name>
例如:将虚拟环境" nlp "添加到 Jupyter,它应该会打印以下内容:
⇒ python -m ipykernel install --user --name=**nlp**
Installed kernelspec nlp in /Users/admin/Library/Jupyter/kernels/**nlp**
之后,您可以cd进入 env 文件夹并检查配置文件kernel.json
现在你可以在 Jupyter 笔记本中选择环境作为内核。这看起来是这样的:

从 Jupyter 笔记本中选择一个虚拟环境

在打开的笔记本中更改虚拟环境
从 Jupyter 笔记本中删除虚拟环境
删除虚拟环境后,您还需要将其从 Jupyter 中删除。先来看看有哪些内核可用。您可以使用以下命令列出它们:
⇒ jupyter kernelspec list
Available kernels:
d2l /Users/admin/Library/Jupyter/kernels/d2l
nlp /Users/admin/Library/Jupyter/kernels/nlp
...
现在,要卸载内核,您可以键入:
jupyter kernelspec uninstall <my_env_name>
尽情享受吧!
仅此而已。感谢阅读。
使用 Python 创建你想要的任何形状的单词云
创建漂亮单词云的分步指南

词云示例— Twitter 美国航空公司情绪(https://www . ka ggle . com/crowd flower/Twitter-Airline-情绪)
数据可视化(如图表、图形、信息图等。)为企业提供了交流重要信息的价值,但如果您的数据是基于文本的呢?如果你希望惊人的可视化格式突出重要的文本数据点,那么使用单词云。
如果你不熟悉单词云,它是由一组单词组成的图片,其中每个单词的大小代表频率或重要性。单词越大、越粗,在一篇文章中被提到的次数就越多,也就越重要。字云易读易懂。关键词对读者来说很突出,并且在视觉上吸引观众。
然而,你可能会厌倦看到单词 cloud 的简单形式。如果我告诉你,WordCloud 也可以根据我们的喜好定制。在本文中,我们将探索如何在 python 中生成您想要的任何形状的单词云。那么,我们开始吧。
如果想看这篇文章的完整代码,请访问我的 github 。第一步,安装将要使用的包,即 wordcloud 。打开终端(Linux / macOS)或命令提示符(windows)并键入:
$ pip install wordcloud
我们将从对互联网上的一篇文章进行网络搜集开始。如果你对网页抓取不熟悉,建议你看一下我之前的一篇文章,标题是 用 Python 制作 4 行网页抓取新闻 。
抓取网站的简单方法
towardsdatascience.com](/scraping-a-website-with-4-lines-using-python-200d5c858bb1)
在这篇文章中,我将从维基百科上抓取标题为' 冰淇淋 ' 的新闻。
from newspaper import Articlearticle = Article('[https://en.wikipedia.org/wiki/Ice_cream'](https://en.wikipedia.org/wiki/Ice_cream'))
article.download()
article.parse()
我们只取文章的正文,也就是:
article.text
简单词云
我们先做一个简单的单词云。第一步是导入我们将使用的依赖项。
from wordcloud import WordCloud
import matplotlib.pyplot as plt
这里我们用的是 wordcloud 库和 matplotlib。wordcloud 库用于生成单词云,matplotlib 用于显示单词云的结果。之后我们调用词云函数,显示词云。
wc = WordCloud()
wc.generate(article.text)
plt.imshow(wc, interpolation="bilinear")
plt.axis('off')
plt.show()
这是我们创造的简单单词云的结果。

简单词云
此外,wordcloud 函数有参数,包括:
- 背景颜色=背景的颜色
- max_words =使用的唯一字的最大数量
- 停用词=停用词列表
- max_font_size =最大字体大小
- random_state =确保在
- 相同的顺序,所以即使生成多次,结果也是一样的
- 宽度=输出的宽度大小
- height =输出的高度大小
让我们尝试使用上面的参数。首先,让我们导入 wordcloud 库提供的停用词
from wordcloud import STOPWORDS
然后我们输入下面的代码
wc = WordCloud(background_color="white", max_words=2000,
stopwords=STOPWORDS, max_font_size=256,
random_state=42, width=500, height=500)
wc.generate(article.text)
plt.imshow(wc, interpolation="bilinear")
plt.axis('off')
plt.show()
这就是结果。

带参数调整的简单单词云
添加自定义字体
我们也可以改变使用的字体。你可以从网站https://www.dafont.com下载字体供个人使用。接下来,在参数中输入字体的路径。
font_path = 'path/to/font'
wc = WordCloud(stopwords=STOPWORDS, font_path=font_path,
background_color="white", max_words=2000,
max_font_size=256, random_state=42,
width=500, height=500)
wc.generate(article.text)
plt.imshow(wc, interpolation="bilinear")
plt.axis('off')
plt.show()
这就是结果

自定义字体
添加自定义遮罩
接下来我们将为单词 cloud 添加一个遮罩。请记住,所用图像的背景必须是白色的,否则,系统会将背景视为物体。另外,背景不能是透明的,因为透明的颜色会被认为是黑色。我将使用下面的图像作为一个面具。

图像遮罩
我们需要添加一些依赖项来加载图像。
from PIL import Image
import numpy as np
接下来,在参数中输入字体的路径。
mask = np.array(Image.open('path/to/image'))
wc = WordCloud(stopwords=STOPWORDS, font_path=font_path,
mask=mask, background_color="white",
max_words=2000, max_font_size=256,
random_state=42, width=mask.shape[1],
height=mask.shape[0])
wc.generate(article.text)
plt.imshow(wc, interpolation="bilinear")
plt.axis('off')
plt.show()
这就是结果。

掩蔽词云
调整颜色
我们还可以调整单词 cloud 中使用的颜色。基本上,我们可以自由决定我们将使用的颜色,但在这篇文章中,我将讨论相当常用的颜色。我们只用一种颜色。但是,我们必须定义要使用的函数。
def one_color_func(word=None, font_size=None,
position=None, orientation=None,
font_path=None, random_state=None):
h = 160 # 0 - 360
s = 100 # 0 - 100
l = 50 # 0 - 100return "hsl({}, {}%, {}%)".format(h, s, l)
使用的颜色格式是 HSL 格式(色调、饱和度、亮度)。更多详情,请访问 HSL 颜色选择器 了解更多关于所用颜色的信息。那么要形成词云,我们所要做的就是将我们已经创建的函数添加到词云函数中。
wc = WordCloud(stopwords=STOPWORDS, font_path=font_path,
mask=mask, background_color="white",
max_words=2000, max_font_size=256,
random_state=42, width=mask.shape[1],
height=mask.shape[0], color_func=one_color_func)
wc.generate(article.text)
plt.imshow(wc, interpolation="bilinear")
plt.axis('off')
plt.show()
图像会是这样的。

一种颜色
除此之外,我们还可以在一定范围内随机产生相似的颜色。我将在明度中添加一个随机函数来调整颜色的亮度。
def similar_color_func(word=None, font_size=None,
position=None, orientation=None,
font_path=None, random_state=None):
h = 40 # 0 - 360
s = 100 # 0 - 100
l = random_state.randint(30, 70) # 0 - 100return "hsl({}, {}%, {}%)".format(h, s, l)
然后,和以前一样。将函数输入到 wordcloud 函数中。
wc = WordCloud(stopwords=STOPWORDS, font_path=font_path,
mask=mask, background_color="white",
max_words=2000, max_font_size=256,
random_state=42, width=mask.shape[1],
height=mask.shape[0], color_func=similar_color_func)
wc.generate(article.text)
plt.imshow(wc, interpolation="bilinear")
plt.axis('off')
plt.show()
结果会是这样的。

相似的颜色
此外,我们可以定义我们将使用的许多颜色。举个例子。
def multi_color_func(word=None, font_size=None,
position=None, orientation=None,
font_path=None, random_state=None):
colors = [[4, 77, 82],
[25, 74, 85],
[82, 43, 84],
[158, 48, 79]]
rand = random_state.randint(0, len(colors) - 1)return "hsl({}, {}%, {}%)".format(colors[rand][0], colors[rand][1], colors[rand][2])
并将该功能添加到 wordcloud 功能中。
wc = WordCloud(stopwords=STOPWORDS, font_path=font_path,
mask=mask, background_color="white",
max_words=2000, max_font_size=256,
random_state=42, width=mask.shape[1],
height=mask.shape[0], color_func=multi_color_func)
wc.generate(article.text)
plt.imshow(wc, interpolation="bilinear")
plt.axis('off')
plt.show()
结果是这样的。

多种颜色
最后但同样重要的是,根据蒙版生成颜色。我们将需要 wordcloud 库提供的功能。
from wordcloud import ImageColorGenerator
然后添加蒙版颜色,将函数添加到 wordcloud 函数中。
mask_colors = ImageColorGenerator(mask)
wc = WordCloud(stopwords=STOPWORDS, font_path=font_path,
mask=mask, background_color="white",
max_words=2000, max_font_size=256,
random_state=42, width=mask.shape[1],
height=mask.shape[0], color_func=mask_colors)
wc.generate(article.text)
plt.imshow(wc, interpolation="bilinear")
plt.axis('off')
plt.show()
这是最后的结果。

生成的颜色
正如我们所看到的,单词云的颜色遵循原始图像的颜色。
所以对于这篇文章,我希望你能从我所说的中获得新的知识。如果你有其他看法,请写在评论里。以后我会分析这个词云的用法进行文本分析。
创建您的第一个聊天机器人!

图片来自 Pixabay 的LukáSKU cius
30 秒解释聊天机器人如何工作
无论您是数据科学家、数据分析师还是软件工程师;无论你是否对 NLP 工具和方法有很强的把握,如果你在这里,你可能想知道聊天机器人是如何工作的,如何建立一个,但从来没有这个需要或机会。嗯……你现在在这里,所以让我们把它做好。
你会惊讶地发现,你很可能对创建自己的聊天机器人很熟悉
用例?
可能是查询一个简单的数据库、订购、预订、客户服务等等。我们每天都和聊天机器人互动。
里面是什么?
聊天机器人都是关于所谓的规则匹配引擎。
以最简单的形式;这就意味着当你收到一条信息时,你会怎么处理它?
一种方法是重复最初输入的内容。虽然这看起来过于简单和无趣,但是在你使用聊天机器人进入更复杂的领域之前,这个想法是一个很好的基础。
让我们把手弄脏吧
def parrot_talk(incoming_message):
bot_response = "Hi, my name is Randy the Parrot, you said: " + message
return bot_response
print(parrot_talk("hello!"))
显然这是一个简单的例子,让我们把它提高一个档次。
responses = {
"Hello": "Hey! How can I help you?",
"I need a refund": "I'm happy to help, can you give me more detail?"
}
def respond(message):
if message in responses:
return responses[message]
respond("I need a refund?")
类似于你第一次看到的,这是一个客服聊天机器人。我们在上面的字典中所做的是建立与我们的客户可能说的话相关的关键字…这些关键字然后映射到适当的响应。
显然,这里的限制是,它要求消息与字典中的键完全相同。
我们可以很快变得非常严格,对任何给定的消息使用正则表达式,创建一个标志来指示文本中各种术语的存在&然后关闭该标志来填充我们的响应。
为了更进一步,我们可以部署 ML 算法,该算法可以预测消息是否属于给定的意图或主题,然后我们可以将其映射回适当响应的字典。
挑战
你见过 LinkedIn 上的自动回复吗?你应该试着通过点击这些提示来进行对话…除了有趣,这也是对复杂和缺乏复杂的有趣探索。对于聊天机器人来说,最困难的事情之一是跟踪任何给定对话状态的能力,一旦你在 LinkedIn 上进行聊天,这一点就会非常明显。
结论
乍看之下,聊天机器人非常容易创建。祝数据科学快乐!
Linux 服务器中的 Cron 作业入门:初学者完全教程

照片由 Sai Kiran Anagani 在 Unsplash 上拍摄
动手教程
使用 cron 自动化您的日常工作
目录(仅适用于 web)
1 [What are cron, cron job, and crontab?](#bed8)
2 [Understand a cron job syntax](#4a20)
3 [How to handle an error on your cron job](#f0c2)
• [Send output to a specific file](#5f39)
• [Use /dev/null](#99b9)
4 [Write a simple cron automation script](#d7e8)
5 [Conclusion](#2c02)
6 [References](#62e2)
什么是 cron、cron job 和 crontab?
Cron 是一个帮助 Linux 用户安排任何任务的系统。然而,cron 作业是在给定时间段内运行的任何定义的任务。它可以是一个 shell 脚本或一个简单的 bash 命令。Cron job 帮助我们自动化我们的日常任务,它可以是每小时,每天,每月等。
注意:在大多数 Linux 系统中,我们必须获得系统管理员的许可,才能定义
**crontab**中列出的特定 cron 作业
同时,crontab 代表 cron 表。这是一个包含 cron 作业列表的 Linux 系统文件。我们在 crontab 中定义我们的任务——bash 命令、shell 脚本、Python 脚本等等。
**# Check cron service on Linux system**
sudo systemctl status cron.service

检查 Linux 系统上的 cron 服务(图片由作者提供)
理解 cron 作业语法
是时候在**crontab**上学习 cron 作业语法了。
**crontab -a <filename>**:新建一个**<filename>**作为 crontab 文件**crontab -e**:编辑我们的 crontab 文件,或者创建一个不存在的文件**crontab -l**:显示我们的 crontab 文件**crontab -r**:删除我们的 crontab 文件- 显示我们上次编辑 crontab 文件的时间
**minute(s) hour(s) day(s) month(s) weekday(s) command(s)**

crontab 文件中六列的描述(图片由作者提供)
注意:日名 0–6 以星期日开始。我们可以很容易地确定我们在 https://crontab.guru/的行程
如何处理 cron 作业中的错误
如果 cron 作业遇到错误,默认情况下,它会向系统管理员发送一封电子邮件。相反,当我们遇到错误时,我们将找出两种常见的方法。
1 将输出发送到特定文件
这是一种常见的方式,我总是在我的 cron 工作中使用它。很简单。我们只需要创建一个文件来保存我们的 cron 作业日志。它将打印出输出,以防作业正确完成,或者如果失败,打印出一个错误。
在本教程中,它只是创建了一个**log.out**文件。输出将被重定向到**log.out**。
* * * * * cd /home/audhi && /bin/bash shell-script.sh >> log.out
crontab 文件中上述语法的描述如下。
*** * * * ***意味着一个任务将在一周的每一天、每月的每一天、每小时的每一分钟被执行- 目录将切换到 shell-script.sh 所在的
**/home/audhi** **/bin/bash**是 Bash shell 的路径和可执行文件**>>**符号将把输出附加到一个现有文件中(**log.out**),而单个**>**符号将覆盖该文件**shell-script.sh**是某个 shell 脚本

Linux 系统上的 crontab 文件(图片由作者提供)
注意:我们需要在 crontab 中编写完整清晰的命令。需要使用
**cd**指定文件位置
2 使用/dev/null
我们可以轻松地将 cron 作业日志和错误发送到**dev/null**,而不是通过电子邮件发送警报。无论我们向**dev/null**发送或写入什么,都将被丢弃。
* * * * * cd /home/audhi && /bin/bash shell-script.sh > /dev/null 2>&1
命令的简短描述:
**> /dev/null**告诉 cron 将输出(STDOUT)重定向到**/dev/null****2**是标准错误 (STDERR)的文件描述符**&**是文件描述符的符号(没有它,后面的**1**将是文件名)**1**是标准输出 (STDOUT)的文件描述符
注意:2>&1 告诉 cron 将所有错误(STDERR)重定向到与标准输出(STDOUT)相同的位置
编写一个简单的 cron 自动化脚本
为了完成本文,我创建了一个 Python 脚本来演示如何使用 cron 作业。这个 Python 脚本将从印度尼西亚最大的在线新闻之一 Kompas News 中收集新冠肺炎数据。你可以在我的 GitHub repo 找到我的新冠肺炎数据网页抓取的 Python 脚本。它的文件名是**Web Scraping Covid-19 Kompas News.py**。
打开我们的终端,键入**crontab -e**打开一个 crontab 文件。然后,向下滚动并键入以下命令。
5 16 * * * cd 'covid19 data' && /usr/bin/python3 'Web Scraping Covid-19 Kompas News.py' >> test.out
crontab 文件中上述语法的描述如下。
- crontab 位于
***/home***而我的脚本在***/home/covid19 data***所以我们需要先切换到***/home/covid19 data*** **python3**解释器位于**/usr/bin/python3**- 输出将被重定向到
***/home/covid19 data***中的**test.out**文件
注意: cron 使用本地时间
还可以学习Apache air flow作为作业编排来自动化常规任务!**
**** [## Apache Airflow 作为新冠肺炎数据的作业编排(通过电子邮件和电报发送通知)
印度尼西亚新冠肺炎数据的网络采集
medium.com](https://medium.com/analytics-vidhya/apache-airflow-as-job-orchestration-e207ba5b4ac5)
结论
cron 作业在 Linux 系统上运行,以运行和执行我们的常规任务(终端命令)。关于 cron 作业,要学习的最重要的事情是终端上的 bash 命令,如何设置我们的任务调度,并确保在我们的脚本在生产环境中运行时捕捉到所有的可能性,以便我们可以防止错误。
参考
[1] Schkn。Linux 上的 Cron Jobs 和 Crontab 讲解(2019)https://dev connected . com/Cron-Jobs-and-Crontab-on-Linux-Explained/。
[2] C .默里。 用实例了解 Linux 中的 Crontab(2019)https://Linux handbook . com/Crontab/# quick-introduction-to-key-cron-concepts。
[3]阿加莎。克龙约伯: 潘端冷卡普 untuk 佩穆拉 2020(2020)。****
在 Apache Beam 中创建您的第一个 ETL 管道

在这篇文章中,我将为您的 Python 应用程序介绍另一个 ETL 工具,叫做 Apache Beam 。
什么是阿帕奇光束?
根据维基百科:
Apache Beam 是一个开源的统一编程模型,用于定义和执行数据处理管道,包括 ETL、批处理和流(连续)处理..
与气流和路易吉不同,阿帕奇 Beam 不是服务器。它是一个包含一组 API 的编程模型。目前,它们可用于 Java、Python 和 Go 编程语言。典型的基于 Apache Beam 的管道如下所示:
(图片来源:https://beam . Apache . org/images/design-your-pipeline-linear . SVG))
从左边开始,从数据库中获取数据(提取),然后经过多个转换步骤,最后将其存储(加载)到数据库中。
让我们讨论一些 Apache Beam 中使用的术语:
- 管道 :-一条管道封装了整个数据处理体验;从数据采集到加载到数据存储。
- p 集合 :-是数据的集合。数据可以是来自固定源的有界的或来自单个或多个流的无界的。
- PTransform :- 它是一个作用于p 集合中每个元素的进程。
- ——一个可移植的 API 层,帮助创建在不同引擎或运行程序上执行的管道。目前支持 Direct Runner(用于本地开发或测试目的)、 Apache Apex、Apache Flink、Gearpump、Apache Spark 和 Google DataFlow。
发展
使用pip安装 Python SDK:
pip install apache-beam
Apache Beam SDK 现在已经安装好了,现在我们将创建一个简单的管道,它将从文本字段中读取行,转换大小写,然后反转。
以下是管道的完整程序:
导入必要的库后,我们将调用PipelineOptions进行配置。例如,如果你正在使用谷歌云数据流,那么你需要传递必要的选项,如项目名称或云名称等。您还可以在它的flag参数中传递命令行参数,例如,输入和输出文件名。
第一步是数据摄取或获取,我们将调用ReadFromText从文本文件中读取数据。管道符号(|)是一个重载操作符,它将PTransform应用于PCollection。如果你使用过 Linux 管道,你应该不难理解。在我们的例子中,集合是通过ReadFromText产生的,然后通过ParDo a 函数传递给ToLower()。Pardo对PCollection的每个元素应用一个函数。在我们的例子中,它运行在文件的每一行。如果您在ToLower()函数中添加一个print()命令,您会看到它将遍历集合并打印存储在element变量中的每一行。我们构造一个 JSON 对象,并将每个元素的内容存储在其中。之后,它通过另一个PTransform,这次是通过ToReverse来反转内容。最后通过调用WriteToText函数将数据存储在文本文件中。当您使用file_name_suffix参数时,它会创建带有适当扩展名的输出文件,例如对于我们来说,它创建为processed-00000-of-00001.txt。默认情况下,Apache Beam 创建多个输出文件,这是在分布式系统上工作时的一种习惯。这些文件的原始内容是:
巴基斯坦的冠状病毒病例在一天内翻了一番,周一迪拜的总数为 106 例:在信德省当局确认 53 例新病例后,巴基斯坦的冠状病毒病例周一已上升至 106 例。信德省现在是巴基斯坦疫情最严重的省份,截至周一下午,共报告了 106 例冠状病毒病例中的 88 例。这是迄今为止该国新型冠状病毒病例增加最多的一次。信德省首席部长法律、反腐败机构和信息顾问穆尔塔扎·瓦哈卜(Murtaza Wahab)周一在推特上说,从与伊朗接壤的塔夫坦边境隔离区返回的 50 人新冠肺炎病毒检测呈阳性
在第一次转换时,它会将所有字符转换成小写。例如如下所示:
巴基斯坦的冠状病毒病例在一天内翻了一番,周一迪拜的总数为 106 例:在信德省当局确认 53 例新病例后,巴基斯坦的冠状病毒病例周一已上升至 106 例。
正如你所看到的,我已经返回了一个字典列表。这样做的原因是,如果我不这样做,它会在一行返回一个字符,所以冠状病毒会变成:
c
o
r
o
n
a
v
I
r
u
s
这是不希望的。我还不知道为什么会发生这种情况,把一行单词分成单个的字符,但是现在,我找到的解决方法是返回一个字典列表。在最后一次转换中,我不带任何词典返回。运行后,将创建一个名为processed-00000-of-00001 . txt的文件,该文件将包含以下内容:
从第 601 天起,我就不在这里了
。根据第 601 号法令第 35 条的规定,难民事务高级专员办事处将向难民事务高级专员办事处提供援助
。你知道吗?我不知道你在说什么。没有任何迹象表明,佛陀 601 号公路上的幸存者已经死亡
91-2005 年,全国人大常委会通过了《全国人大常委会关于维护互联网安全的决定》
如您所见,该文件现在包含相同的内容,但顺序相反。
结论
Apache Beam 是编写基于 ETL 的应用程序的好工具。我只是讨论了它的基本原理。您可以将它与云解决方案集成,并将数据存储到典型的数据库中。我希望您会发现它很有用,并将在您的下一个应用程序中尝试它。
与往常一样,代码可以在 Github 上获得。
原载于 2020 年 3 月 27 日http://blog . adnansiddiqi . me。
创建您自己的数据科学课程

约翰·施诺布里奇在 Unsplash 上的照片
如何设计个性化的数据科学学习路径
随着数据科学领域在过去十年中的发展,在线课程、学位课程和训练营的数量也在增加,这些课程和训练营有望教会你成为数据科学家所需的一切。尽管这些课程中有许多会为你提供核心原则的坚实基础,但它们绝不是针对你个人的。
随着现在数据科学可用的学习资源数量的增加,对于许多人来说,创建自己的定制学习课程可能是最佳选择。通过创建个性化的学习路径,你将只学习你需要学习的东西,深入到特别适合你的目标的领域,并且在大多数情况下,与支付学位课程或训练营相比,花费要少得多。
在下面的文章中,我将描述为什么为数据科学创建自己的课程是一个好主意,如何开始以及如何在没有老师或讲师的情况下保持继续学习的动力。
决定你想成为什么
数据科学是一个广阔的领域,事实上,有许多不同类型的角色可以在数据科学的保护伞下进行分类。就所需的技能组合而言,尤其是某些技能所需的知识深度而言,这些角色各不相同。
例如,机器学习工程师的角色将需要深入的编程和数据工程知识,因此这类角色的课程重点将更接近软件工程技能。而从事新算法和技术研究的数据科学家需要更广泛的数学和统计概念知识。
因此,提前确定你最感兴趣的数据科学领域,然后围绕你需要发展的特定技能设计课程至关重要。
你已经知道了什么?
由于数据科学是一个相对较新的领域,许多学习数据科学的人已经拥有了通过以前的工作或学术研究获得的技能和经验。在设计你的课程时,考虑你已经掌握的可以转移的技能是很重要的。
例如,如果你已经获得了一个数学学科的博士学位,那么你可能已经具备了所需的数学概念的必备知识。因此,你的课程可能更适合获取软件工程技能。然而,如果你以前做过软件工程师,这是进入数据科学越来越常见的途径,那么你的重点可能是获取机器学习算法背后的数学和统计学理论知识。
你需要学习什么?
一旦你知道了你最感兴趣的数据科学的具体领域,并从以前的研究或工作经验中确定了任何可转移的技能,就该列出你需要学习的技能了。
要做到这一点,首先要看看所有数据科学家都需要的核心技能,不管是在哪个特定领域。如今,这通常是 python、SQL、数据分析、机器和深度学习、数据工程,以及至少对机器和深度学习背后的数学和统计学的基本理解。如果你还没有这些领域的知识或经验,那就把它们添加到你的列表中。
接下来,你需要看一些你感兴趣领域的招聘广告。每份工作列出的要求将会给你一个很好的主意,在这些领域中你需要获得更深层次的知识。然后,您可以将这些添加到您的列表中。
确定你的学习风格
不同的人用不同的方式学得最好。有些人通过视觉和听觉方法学得最好,如幻灯片和视频,有些人喜欢单独或集体学习,而另一些人更喜欢通过做来学习。
20 世纪 70 年代,新西兰教师尼尔·弗莱明创造了学习风格的瓦尔克模型。这个模型将学习风格分为七种不同的类型。传统课程假设每个人通过使用特定的媒介都能学得最好。然而,我相信要真正尽可能高效地学习,找到最适合你个人学习风格的合适材料是很重要的。为了了解你是哪种类型的学习者,你可以参加这个测验。
有大量不同的学习材料可用于获取数据科学职业所需的技能。如果你是一个实用的学习者,你可以尝试基于浏览器编程的课程,如 Dataquest 和 codeacademy ,或者尝试参加 kaggle 竞赛。如果你通过讲座和视频学得更好,那么 coursera 有一系列使用这种材料的课程。
庆祝你的成功
最后,一旦你确定了你需要学习的技能和你想如何学习它们,你需要决定一种方法来跟踪你的进步,这样你就可以庆祝你的成就。
我建议创建一个学习路线图。这不必是什么花哨的东西,我用谷歌表跟踪我的。重要的是找到一种方法来记录你正在学习的技能,并包括一种方法来标记或记录你在这些技能上的进展。
我用来学习数据科学的路线图如下图所示。这包括一个带有评分系统的谷歌表单上的一长串技能。每月一次,我会对照这个技能和熟练程度列表给自己打分,并与上个月进行比较。

通过记录你的进步,并定期停下来庆祝你的成功,你将保持动力继续学习你的课程。
概括地说,要为学习数据科学创建量身定制的课程,您需要采取以下步骤:
- 决定你最感兴趣的数据科学的具体领域。
- 确定你已经拥有的任何可转移的技能。
- 列出你需要学习的技能。
- 了解你的学习方式,找到最适合你的资源。
- 想办法跟踪你的进步,定期庆祝你的成功。
关于学习数据科学的完全免费资源列表,请参见我以前的文章— 如何免费学习数据科学。
要了解如何加快学习速度,请参见— 学习数据科学的最快方法。
感谢阅读!
用熊猫创建你自己的数据框架
创建样本数据框的简单方法

由 Unsplash 上的 chuttersnap 拍摄
Pandas 是一个非常强大的 Python 数据分析库,可以加速项目的预处理步骤。在这篇文章中,我将介绍用熊猫创建样本数据框的不同方法。
练习是学习任何学科的关键基础。在编码中更是如此。为了建立流畅的编码技能,练习起着关键的作用。因此,在学习和练习数据分析和操作的基础知识时,创建自己的样本数据框架可能比在网上搜索合适的数据框架更方便。Pandas 提供了许多方法来创建具有所需形状和特征的样本数据帧。
让我们来看看创建自己的数据框架的不同方法。一如既往,我们从进口熊猫开始。
import pandas as pd
import numpy as np
我们可以创建一个字典并直接将其转换为数据帧:
dict_a = {'col_a':[1,2,5,8],
'col_b':['John','Nancy','Adam','Julia'],
'col_c':[True,True,False,True]}df_a = pd.DataFrame(dict_a)

我们甚至不需要指定数据类型,因为 pandas 能够推断出它们:

df_a 是一个相对较小的数据帧。对于某些任务,我们可能需要更大的数据框架,但是键入一个有许多条目的字典是乏味的。在这种情况下,我们可以使用 numpy 来创建样本数组。然后,这些数组可以用作字典中的值:
dict_b = {'col_a': np.random.randn(50),
'col_b': np.random.randint(10, size=50)}df_b = pd.DataFrame(dict_b)df_b.shape
(50,2)
np.random.randn(50) 创建 50 个正态分布的值, np.random.randint(10,size=50) 创建 50 个介于 0 和 10 之间的整数值。正如我们所看到的,结果数据帧的大小是(50,2)。让我们看看前 5 行:

我们还可以用 numpy 创建二维数组,并将这些数组直接转换成数据帧。要用 np.random.randint 创建二维数组,我们需要将一个元组传递给 size 参数:

df_c = pd.DataFrame(np.random.randint(10, size=(6,4)))

Pandas 分配整数列名,但是我们可以使用列参数来改变它:
df_d = pd.DataFrame(np.random.randint(10, size=(6,4)),
columns=['a','b','c','d'])

我们也可以改变索引值。这次让我们使用 np.random.randn 创建一个二维数组:

然后我们将使用 pandas 的 date_range 函数定义一个时间序列索引。然后将该索引传递给索引参数:
index = pd.date_range('2020-01-01','2020-01-05')df_e = pd.DataFrame(np.random.randn(5,4),
columns=['a','b','c','d'],
index=index)

我们还可以使用 dtype 参数指定数据类型。回想一下我们创建的第一个数据帧。熊猫从值中推断出数据类型。让我们用指定的数据类型创建相同的数据帧:
dict_a = {'col_a':[1,2,5,8],
'col_b':['John','Nancy','Adam','Julia'],
'col_c':[True,True,False,True]}df_a = pd.DataFrame(dict_a, dtype='category')

数据帧看起来相同,但数据类型不同:

我们也可以使用多个字典来创建一个数据框架。我们创建一个字典列表,并将其输入到 pd。数据帧函数。字典的值将按照它们在列表中的顺序插入数据帧:
dict_a = {'col_a':[1,2,5,8],
'col_b':['John','Nancy','Adam','Julia'],
'col_c':[True,True,False,True]}dict_b = {'col_a':[1,7,9,18],
'col_b':['a','d','c','t'],
'col_c':[True,False,False,True]}list_g = [dict_a, dict_b]df_g = pd.DataFrame(list_g)
但是,通过这种方式,字典的值将被合并并放入数据帧的一个单元格中:

熊猫的一大优点是通常有多种方法来完成一项任务。所以,千万不要把自己局限在一种方式上,去寻找不同的方式和解决方法。用这种观点处理简单的任务是很重要的,因为这也有助于解决复杂的问题。
感谢您的阅读。如果您有任何反馈,请告诉我。
用 Python 创建自己的 NFL 触地得分道具

Izaac Crayton 在 Unsplash 上拍摄的照片
用泊松分布模拟离散事件的统计框架
动机
我很兴奋地展示一些推断方法来估计触地道具,因为这些方法本身非常强大,并且有多种应用。最大的好处是,根据定义,推断方法估计目标变量的潜在分布。在这种情况下,这意味着我知道一个球员投出 2 次触地得分、3 次触地得分、4 次触地得分或 10 次触地得分的可能性有多大,而不仅仅是一个平均值。了解整个分布很重要,因为道具从来不会问你点估计。当然,除了 props 之外,这些发行版还有许多应用。例如,您可能想知道在一段固定的 DNA 上由于辐射导致的预期突变的数量,或者一年中由于机械故障导致的飞机坠毁的数量。运动更有趣,但我不得不承认它们在现实生活中不那么重要。
其次,相对于传统的统计技术,过去我在黑盒机器学习模型方面有着不成比例的经验。从 Keras API 导入密集层可以解决很多问题,但这并不令人满意。很难回答这样的问题,这个模型是否过拟合?我的模型在做什么?有了一点经验,用推理来回答这类问题就容易多了。
贝叶斯推理
当我谈到推理模型时,我通常指的是贝叶斯推理。贝叶斯推理允许我们使用先验信息来估计我们的目标。你很少会对你试图估算的东西毫无头绪。贝叶斯推理允许我们创建一个“弱信息”先验。我知道一个球员每场比赛的传球触地得分是积极的。我知道这不会是什么荒谬的事情,比如每场比赛 20 次触地得分。我可以在制作模型时使用这类信息。
假设我们想估计拉马尔·杰克逊在 2019 赛季第 3 周的传球达阵输出。我从小到大上的统计课对这个问题没有很好的解决方法。一种方法可能是平均他在第一周和第二周的产量,并以此作为猜测。或者,我们可以使用上一季的平均值。很明显,这两种方法都有缺陷。在第一周和第二周,他平均 3.5 次传球达阵。熟悉足球的人都知道,场均 3.5 次传球达阵在低量传球进攻中是完全史无前例的。他还打了一个非常弱的迈阿密海豚队,这将夸大他的数字。去年,他在常规赛中平均每场比赛有 0.86 次触地得分。即使有更大的样本量,这也不能令人满意。他很年轻,他可能在休赛期取得了一些进步。该团队还致力于围绕他的技能与人员。
很容易说他的传球触地得分会在 0.85 到 3.5 之间。很难说他的传球输出会在 0.85 到 3.5 之间的哪个点结束。这就是贝叶斯推理可以帮助我们的地方。
边际可能性
贝叶斯方法为我们提供了一种数学上可靠的方法,将先验估计与小样本数据结合起来。我想远离密集的数学,但我也认为很重要的是要注意到,在我们拥有强大的个人电脑之前,贝叶斯推理是不太可能的。如果非要我猜的话,这就是为什么它们在传统的统计学课上不被强调的原因。贝叶斯推断需要估计边际可能性,那是极其困难的。这是维基百科的解释:
不幸的是,边际可能性通常很难计算。已知一小类分布的精确解,特别是当被边缘化的参数是数据分布的 共轭先验 时。在其他情况下,需要某种 数值积分 方法,要么是一般方法如 高斯积分 或 蒙特卡罗方法 ,要么是专门用于统计问题的方法如 拉普拉斯近似
实际上,这意味着你可以成为一名世界级的数学家,或者安装 Python 和 R 包来为你完成所有繁重的工作(繁重的工作意味着从后面采样数千次来代替求解积分)。
泊松分布
泊松分布对于我们的着陆推进估算是理想的。如果您不熟悉它们,您可以将它们视为在固定时间段内对计数进行建模的一种良好而简单的方法。例如,假设我每天喝大约 0.86 杯咖啡。我每天咖啡摄入量的泊松分布可以用均值为 0.86 的泊松分布来建模。与正态分布不同,我不需要知道标准差或任何其他参数。方差等于平均值。
那似乎好得难以置信。有时候就是!在现实世界中,随着时间的推移,数据科学家很可能需要更多的参数来更好地建模计数。然而,泊松分布本身是非常强大的,没有进一步的复杂性。
我们可以使用相同的统计框架来模拟我一天喝的咖啡量和拉马尔在一场比赛中触地得分的次数,这很酷。在这篇文章中,我将把重点放在他身上,因为他是一个有趣的案例。他被幻想足球专家预测为 2019-20 年任何 16 场比赛首发中触地得分最低的球员,但最终获得了最多的触地得分。这并不一定意味着幻想分析师的工作很糟糕。离群发生!

如果 mu = 0.86,你会期望大约 41%的时间没有传球触地得分。大约 23%的情况下,你会期望两个或更多。
以下是使用泊松建模所需的假设:
- 接地计数是离散的,不能为负✅
- 触地得分是✅的独立项目
- 触地得分的平均发生率是常数✅
好吧,我承认,这些假设并不完美。在现实世界中,假设几乎从来都不是!平均速度是复杂的,比如两分钟的训练和更多的传球。还有其他可能的方法,如负二项分布或有序逻辑回归。在这种情况下,我认为 Poisson 会以更低的复杂性提供类似的性能。其他离散概率分布值得今后进一步探讨。无论你选择哪种方法,请注意小样本是一个问题,因为一个赛季只有 16 场比赛。
制作一个先验
我需要预先估计一个赛季中一个四分卫每场比赛会投多少次达阵。用外行人的话来说,我是在用以前的足球知识对每个四分卫会投多少次达阵做出有根据的猜测。如果我觉得懒,我可以用全联盟的平均值。然而,仅仅一个平均值就从我们的模型中窃取了有用的信息。我们只有 16 个数据点(有时更少!)来计算这些 QB 在传球达阵方面有多好。所以,让我们用更有力、更有信息的先验知识。
我查阅了 2014 年整个赛季的共识幻想足球预测。根据这些预测,我将专家意见作为先验。我可以更肯定他们会接近真相。当然,我在赛季后写这篇文章,拉马尔度过了职业生涯的一年。我知道追溯过去,那些专家会错的。让我们假装我不知道,因为如果我已经知道了未来,统计分析还有什么意义呢?经过一番计算,我发现每场比赛的实际传球得分与专家意见的方差为 0.22。
下面是我用NFL scraper数据逐季查找每场比赛达阵的 python 代码块。
我正试着练习一些 R(感谢反馈)。这里是 R 中相同的代码。
对于先验我们可以使用什么样的分布?我不想向你抛出另一种分布,但是第三种分布使得数学计算非常简单。我要讲的第三种分布是伽玛分布。伽马分布被称为泊松分布的共轭先验。
与正态分布不同,伽马分布由形状参数 k 和速率参数 β 定义。现在,我只有平均值和方差。这些可以用一点代数很容易地转换:
平均值= k / β
方差= k / β
对于平均值,我使用 FantasyPros 共识预测值代入 1.1 TD/G 的平均预测值。对于方差,我使用 0.22,这是我之前找到的。在这一切之后,我们终于有了拉马尔·杰克逊传球达阵的先验,这是基于对 2019 年的共识幻想预测:

检查你的先验是否有意义总是一个好主意。请注意,在 1.1 下有很大的可能性,但在 0 时可能性接近于零。从历史触地得分率来看,传球触地得分率几乎为零有点荒谬。此外,我们现在知道拉马尔·杰克逊在 MVP 赛季的场均得分约为 2.4。我们预计 2.4 有非零的可能性,但仍然非常小。这与分布是一致的。
更新先验

更新我们的伽马分布出奇的容易。我们实际上只是将数据添加到形状和速率参数中:
**import scipy.stats as ss
import numpy as np# k = shape parameter (found above)
# b = rate parameter# 100 decimals between 0 and 8 to create a smooth line
x = np.linspace(start=0, stop=8, num=100) # y = np.array([ ... season touchdown counts ])def posterior(x,y): shape = k + y.sum()
rate = b + y.size
return ss.gamma.pdf(x, shape, scale=1/rate), shape, rate**
函数只有 3 行,说明 Gamma 是个不错的选择!请注意,随着季节数据量的增加,我们对先验的依赖越来越少。此外,随着猜测的进行,我们会变得更加确定。通过许多比赛,我们可以对速度非常有信心。不幸的是,对于我们这些糟糕的数据科学家来说,由于伤病、自由球员签约、教练变更等原因,达阵率可能会随着时间而改变。这种复杂性破坏了我们的假设,因此分析并不完美。
让我们快速检查一个案例,在这个案例中,触地率与期望值相差不远。例如,德肖恩·沃森在 16 场比赛中预计有 27 次触地得分,实际上在 15 场比赛中有 26 次:

在这种情况下,我们验证了我们的先验,并且越来越确定我们是对的!我们得到的德尚沃森的泊松分布在赛季前后看起来完全一样。然而拉马尔:

拉马尔在一场对抗普通防守的比赛中 0 次触地得分的概率从大约 32%到大约 13%!
调整防御
如果我们要创造令人尊敬的预测,我们需要更多的信息,而不仅仅是谁在打四分卫。我将展示如何调整防御,并将其他效果留给您尝试建模。例如,您可能有多种方法来包括主场优势、每场比赛的传球码数或维加斯总分。然而,在如此小的样本量下,你能模拟的效果是有限的。准确的主场优势可能需要多个赛季的数据。
防御调整可能是戏剧性的。例如,新英格兰全年只允许 13 次传球触地得分。迈阿密在他们的第一场比赛中让了 5 分。我用现代的 R 和 Python 包,实际上建模这些效果真的很容易。这就是所谓的泊松回归。我们简单地构造一个线性函数:
theta =拦截+QB _ 随机 _ 效果+防御 _ 随机 _ 效果
这里的截距项本质上是一个联盟平均值。QB 的“随机效应”是他们投掷达阵球的技巧。投很多传球达阵的 QBs 会有相对高的随机效应,而防很多达阵的防守会有负的随机效应。
我们也可以像 QBs 一样给出防御的模型先验。我使用 5 年的加权平均值作为先验,除了两个例外——亚利桑那州和旧金山——我在我的代码中解释了这一点(链接如下)。
唯一复杂的部分是,我们不能把θ代入泊松分布。我们需要一个链接函数来模拟数据的平均值。对于泊松,这意味着使用 lambda = exp(theta)。我不打算在这里深究链接函数,但是它们在所有类型的回归中都是常见的。
在 Python 中,我使用 PyMC3 对 QBs 建模。这些不是你唯一可以使用的软件包。其实我一般用 pystan。以下是两者的模型代码:
结果
终于!说实话,我以为这篇文章会短很多。这是我对 QB 通过触地投影的结果:

“CI”代表可信区间。类似于置信区间,但是如果你把两者混为一谈,会有人发疯的。
这里有一个防御的例子:

由于样本量小,这些误差线很宽。比如马特·斯塔福德,只打了 8 场。因此,他的误差线比其他人更宽。在我看来,QBs 和 defenses 的排名大致正确。你可以看到幻想足球预测先验的影响,因为尽管拉马尔投出更多的达阵,但布里斯的排名在拉马尔之前。也有可能是拉马尔打的防守更轻松。前科是一种特征,而不是缺陷。信息丰富、准确的先验通常有助于模型的准确性。我们不想对一个赛季反应过度,说拉马尔是联盟中最好的达阵传球手,而在赛季初我们认为他是最差的。前科也不占数据优势,他还是排第二!一个可能的改进是对我们不确定的年轻 QB 使用较高的方差先验,而对已经在联盟中存在很长时间的 QB 使用较低的方差先验。
我们免费得到一个很好的特写。这些排名自然会根据日程安排的强度进行调整。在收集了一个赛季的数据之后,让我们来比较一些假设的比赛。最低预期的传球触地得分比赛将是雅各比·布里塞特对阵芝加哥。最高分是德鲁·布里斯对迈阿密。这些分布应该类似于拉马尔季前赛和季后赛,但由于防守调整,稍微更具戏剧性:

根据模型,布里塞特几乎有 50%的机会不掷达阵传球。预计 Brees 将投出 3 分,但有很大范围的可能结果。
放映超级碗
我想重申,即使我显示出价值,我也不建议下这些赌注。几乎可以肯定,这种模式过于简单,无法超越市场线。我用季后赛数据更新了数据,找到了帕特·马霍斯和吉米·G 的泊松分布:

好,我们可以用这种方法计算这些人覆盖任何触地问题的概率。我查了 DK Sportsbook 的超级碗传球触地得分线。他们有 Pat Mahomes 在-215/+168 超过 1.5 传球 TDs,Jimmy Garappalo 在-112/-112 超过/低于 1.5 传球 TDs。使用泊松回归方法,我有 54%的 Mahomes 通过两个或更多的 TD,有 42%的 Jimmy Garappalo 通过两个或更多的 TD。使用一个隐含的概率计算器,这意味着我显示吉米 G 的价值在-138 以下。我显示了+117 以下的值。
Mahomes 在他的 18 场比赛中有 7 场没有得到 2 分,面对 SF 的强大防守,我认为这就是为什么泊松模型可能低估了他的传球得分。此外,他带伤打了几场比赛,这可能降低了他的“真实”总得分。
实际上,我认为市场可能会有点符合我的数字。他对阵绿湾只传了 8 次,酋长队跑位防守弱。我可能错了。与他们今年的大多数比赛不同,49 人队在这场比赛中更有可能落后,他们在本赛季的几次比赛中得了很多分。
结论
虽然这是一个简单的模型,但泊松回归是一种具有多种应用的强大方法。就像在足球比赛中,人们也可以模仿其他类型的达阵或拦截来命名一对情侣。我喜欢通过这个模型工作,我计划在未来做类似的贝叶斯推理方法。这里是我为这篇文章创建的笔记本的链接。另外,这里有一个类似的例子我跟踪模拟橄榄球比分。
使用 RaspberryPi 和 Tensorflow 创建您自己的智能婴儿监视器

这个故事的更新版本可以在 Platypush 博客 上找到。
你们中的一些人可能已经注意到,距离我的上一篇文章已经有一段时间了。这是因为在此期间,我已经成为一名父亲,我不得不暂时从我的项目中抽出时间来处理一些(还)不能自动化的父母任务。
或者,他们能吗?虽然我们可能还需要几年时间才能拥有完全负责给儿子换尿布的机器人(假设有足够多的疯狂父母同意在自己的孩子身上测试这种设备),但有一些风险较小的父母职责为自动化提供了一些空间。
作为一名父亲,我首先意识到的一件事是,婴儿真的会哭,即使我在家,我也不一定能听到儿子的哭声。商用婴儿监听器通常会填补这一空白,它们充当对讲机,让您即使在另一个房间也能听到宝宝的声音。但我很快意识到,商用婴儿监视器比我想要的理想设备还要笨。它们检测不到宝宝的哭声——它们只是像对讲机一样将声音从声源传到扬声器。当他们移动到不同的房间时,由父母来移动扬声器,因为他们不能在任何其他现有的音频基础设施上播放声音。它们通常配备低功率扬声器,并且通常不能连接到外部扬声器——这意味着如果我在另一个房间播放音乐,我可能会错过我宝宝的哭声,即使显示器与我在同一个房间。而且大多数都是低功率无线电波,这意味着如果婴儿在他/她的房间里,你必须走一小段路到地下室,它们通常不会工作。
所以我带来了一份智能婴儿监视器的说明书。
- 它应该可以在任何简单便宜的东西上运行,比如带有廉价 USB 麦克风的 RaspberryPi。
- 它应该能够检测到我宝宝的哭声,并在他开始/停止哭泣时通知我(最好是在我的手机上),或者跟踪我仪表盘上的数据点,或者在我儿子哭泣时执行任何我想执行的任务。它不应该只是充当一个无声的对讲机,将声音从一个声源传递到一种兼容设备。
- 它应该能够在任何设备上流式传输音频——我自己的扬声器,我的智能手机,我的电脑等。
- 无论声源和扬声器之间的距离有多远,它都可以工作,不需要在房子里到处移动扬声器。
- 它还应该配备一个摄像头,这样我就可以实时检查我的宝宝在做什么,或者当他开始哭的时候,我可以拍一张照片或一个简短的视频,以检查一切都好。
让我们看看如何使用我们最喜欢的开源工具来完成这项工作。
录制一些音频样本
首先,获得一个 RaspberryPi,并在 SD 卡上闪存任何兼容的 Linux OS 最好使用任何 RaspberryPi 3 或更高版本来运行 Tensorflow 模型。还需要一个兼容的 USB 麦克风——任何东西都可以,真的。
然后安装我们需要的依赖项:
[sudo] apt-get install ffmpeg lame libatlas-base-dev alsa-utils
[sudo] pip3 install tensorflow
作为第一步,我们必须在婴儿哭和不哭的地方记录足够的音频样本,我们稍后将使用这些样本来训练音频检测模型。注意:在这个例子中,我将展示如何使用声音检测来识别婴儿的哭声,但同样的程序可以用于检测任何类型的声音——只要它们足够长(例如,警报或邻居的钻孔声),并且在背景噪音中足够大。
首先,看看可识别的音频输入设备:
arecord -l
在我的 RaspberryPi 上,我得到以下输出(注意,我有两个 USB 麦克风):
**** List of CAPTURE Hardware Devices ****
card 1: Device [USB PnP Sound Device], device 0: USB Audio [USB Audio]
Subdevices: 0/1
Subdevice #0: subdevice #0
card 2: Device_1 [USB PnP Sound Device], device 0: USB Audio [USB Audio]
Subdevices: 0/1
Subdevice #0: subdevice #0
我想用第二个麦克风来录音——那就是card 2, device 0。识别它的 ALSA 方式是hw:2,0(直接访问硬件设备)或plughw:2,0(如果需要,推断采样率和格式转换插件)。请确保 SD 卡上有足够的空间,或者插入外部 USB 驱动器,然后开始录制一些音频:
arecord -D plughw:2,0 -c 1 -f cd | lame - audio.mp3
当你的宝宝在同一个房间时,录下几分钟或几个小时的音频——最好是长时间的沉默、婴儿啼哭和其他不相关的声音——完成后按 Ctrl-C 键。尽可能多次重复该过程,以获取一天中不同时刻或不同日期的音频样本。
标记音频样本
一旦你有了足够的音频样本,就该把它们复制到你的电脑上来训练模型了——要么使用scp来复制文件,要么直接从 SD 卡/USB 驱动器中复制。
让我们把它们都放在同一个目录下,例如~/datasets/sound-detect/audio。此外,让我们为每个示例创建一个新文件夹。每个文件夹将包含一个音频文件(名为audio.mp3)和一个标签文件(名为labels.json),我们将使用它们来标记音频文件中的负/正音频片段。因此,原始数据集的结构类似于:
~/datasets/sound-detect/audio
-> sample_1
-> audio.mp3
-> labels.json -> sample_2
-> audio.mp3
-> labels.json ...
现在无聊的部分来了:给录制的音频文件贴标签——如果它们包含你自己的宝宝几个小时的哭声,这可能是特别自虐的。在您最喜欢的音频播放器或 Audacity 中打开每个数据集音频文件,并在每个样本目录中创建新的labels.json文件。确定哭泣开始和结束的确切时间,并在labels.json中以time_string -> label的形式作为键值结构报告它们。示例:
{
"00:00": "negative",
"02:13": "positive",
"04:57": "negative",
"15:41": "positive",
"18:24": "negative"
}
在上面的例子中,00:00 和 02:12 之间的所有音频段将被标记为负,02:13 和 04:56 之间的所有音频段将被标记为正,依此类推。
生成数据集
一旦您标记了所有音频样本,让我们继续生成将被馈送到 Tensorflow 模型的数据集。我创建了一个通用库和一套声音监听工具,名为 micmon 。让我们从安装开始:
git clone git@github.com:/BlackLight/micmon.git
cd micmon
[sudo] pip3 install -r requirements.txt
[sudo] python3 setup.py build install
该模型旨在处理频率样本,而不是原始音频。原因是,如果我们想要检测特定的声音,该声音将具有特定的“频谱”特征,即基频(或基频通常可能落入的狭窄范围)和以特定比率绑定到基频的特定谐波集。此外,这些频率之间的比率既不受振幅的影响(无论输入音量如何,频率比率都是恒定的),也不受相位的影响(无论何时开始录制,连续声音都将具有相同的频谱特征)。与我们简单地将原始音频样本馈送到模型的情况相比,这种幅度和时间不变属性使得这种方法更有可能训练稳健的声音检测模型。此外,该模型可以更简单(我们可以在不影响性能的情况下轻松地将频率分组到频段中,因此我们可以有效地执行降维),更轻便(无论样本持续时间如何,该模型都将有 50 到 100 个频带作为输入值,而一秒钟的原始音频通常包含 44100 个数据点,输入的长度会随着样本持续时间的增加而增加),并且更不容易过拟合。
micmon提供计算音频样本某些片段的 FFT (快速傅立叶变换)的逻辑,使用低通和高通滤波器将产生的频谱分组,并将结果保存到一组 numpy 压缩(.npz)文件中。您可以在命令行上通过micmon-datagen命令来完成:
micmon-datagen \
--low 250 --high 2500 --bins 100 \
--sample-duration 2 --channels 1 \
~/datasets/sound-detect/audio ~/datasets/sound-detect/data
在上面的例子中,我们从存储在~/dataset/sound-detect/audio下的原始音频样本生成数据集,并将结果频谱数据存储到~/datasets/sound-detect/data。--low和--high分别标识在结果频谱中要考虑的最低和最高频率。默认值分别为 20 Hz(人耳可听到的最低频率)和 20 kHz(健康和年轻人耳可听到的最高频率)。但是,您通常可能想要限制此范围,以尽可能多地采集您想要检测的声音,并尽可能多地限制任何其他类型的音频背景和不相关的泛音。我发现在我的情况下,250-2500 赫兹的范围足以检测婴儿的哭声。婴儿的哭声通常很高(考虑到歌剧女高音可以达到的最高音约为 1000 Hz),通常你可能希望至少将最高频率加倍,以确保获得足够的高次谐波(谐波是实际上赋予声音音色或颜色的较高频率),但不会太高,以免被其他背景声音的谐波污染频谱。我还截掉了 250 赫兹以下的任何东西——婴儿的哭声在这些低频上可能不会发生太多,包含它们也可能会扭曲检测。一个好的方法是在 Audacity 或任何均衡器/频谱分析仪中打开一些阳性音频样本,检查哪些频率在阳性样本中占主导地位,并将数据集集中在这些频率周围。--bins指定频率空间的组数(默认值:100)。较高数量的仓意味着较高的频率分辨率/粒度,但如果太高,可能会使模型易于过拟合。
该脚本将原始音频分割成更小的片段,并计算每个片段的频谱“签名”。--sample-duration指定这些片段的长度(默认值:2 秒)。对于持续时间较长的声音,较高的值可能效果更好,但它会减少检测时间,并且可能会在声音较短时失败。较低的值可能更适合较短的声音,但如果声音较长,则采集的片段可能没有足够的信息来可靠地识别声音。
micmon-datagen脚本的另一种方法是通过提供的micmon API 创建自己的脚本来生成数据集。示例:
无论您使用的是micmon-datagen还是micmon Python API,在这个过程的最后,您应该会在~/datasets/sound-detect/data下找到一堆.npz文件,每个文件对应原始数据集中的一个带标签的音频文件。我们可以使用这个数据集来训练我们的神经网络进行声音检测。
训练模型
micmon使用 Tensorflow+Keras 定义和训练模型。使用提供的 Python API 可以很容易地做到这一点。示例:
运行这个脚本之后(并且对模型的准确性感到满意之后),您会发现您的新模型保存在~/models/sound-detect下。在我的情况下,从我的婴儿房间收集大约 5 个小时的声音,并定义一个良好的频率范围来训练一个准确率为 98%的模型就足够了。如果你在你的电脑上训练了这个模型,只要把它复制到 RaspberryPi 就可以开始下一步了。
使用模型进行预测
是时候制作一个脚本了,它使用之前根据麦克风的实时音频数据训练的模型,并在我们的宝宝哭泣时通知我们:
在 RaspberryPi 上运行脚本,让它运行一会儿——如果在过去 2 秒内没有检测到哭声,它将打印negative,否则打印positive。
然而,如果我们的孩子在哭,那么简单地在标准输出中打印一条消息的脚本没有多大用处——我们希望得到通知!让我们用板推盖住这个部分。在本例中,我们将使用[pushbullet](https://platypush.readthedocs.io/en/latest/platypush/plugins/pushbullet.html)集成在检测到哭泣时向我们的手机发送消息。让我们安装 Redis(Platypush 用来接收消息)和 Platypush,并集成 HTTP 和 Pushbullet:
[sudo] apt-get install redis-server
[sudo] systemctl start redis-server.service
[sudo] systemctl enable redis-server.service
[sudo] pip3 install 'platypush[http,pushbullet]'
在你的智能手机上安装 Pushbullet 应用程序,前往 pushbullet.com 获取 API 令牌。然后创建一个~/.config/platypush/config.yaml文件,启用 HTTP 和 Pushbullet 集成:
backend.http:
enabled: Truepushbullet:
token: YOUR_TOKEN
现在,让我们修改前面的脚本,使它触发一个可以被 Platypush 钩子捕获的[CustomEvent](https://platypush.readthedocs.io/en/latest/platypush/events/custom.html),而不是将消息输出到标准输出:
将上面的脚本保存为例如~/bin/micmon_detect.py。只有在window_length秒的滑动窗口内检测到至少positive_samples个样本时,脚本才会触发一个事件(这是为了减少由预测错误或临时故障引起的噪声),并且只有当当前预测从负变为正或相反时,脚本才会触发一个事件。然后该事件通过RedisBus被分派给 Platypush。该脚本还应该具有足够的通用性,可以处理任何声音模型(不一定是哭泣的婴儿)、任何肯定/否定标签、任何频率范围和任何类型的输出事件。
现在让我们创建一个 Platypush 钩子来对事件做出反应,并向我们的设备发送通知。首先,准备 Platypush 脚本目录(如果还没有创建的话):
mkdir -p ~/.config/platypush/scripts
cd ~/.config/platypush/scripts# Define the directory as a module
touch __init__.py# Create a script for the baby-cry events
vi babymonitor.py
babymonitor.py的内容:
现在为 Platypush 创建一个服务文件(如果它还不存在的话),并启动/启用该服务,这样它将在终止或重启时自动重启:
mkdir -p ~/.config/systemd/user
wget -O ~/.config/systemd/user/platypush.service \
[https://raw.githubusercontent.com/BlackLight/platypush/master/examples/systemd/platypush.service](https://raw.githubusercontent.com/BlackLight/platypush/master/examples/systemd/platypush.service)systemctl --user start platypush.service
systemctl --user enable platypush.service
并为婴儿监视器创建一个服务文件—例如~/.config/systemd/user/babymonitor.service:
[Unit]
Description=Monitor to detect my baby's cries
After=network.target sound.target[Service]
ExecStart=/home/pi/bin/micmon_detect.py -i plughw:2,0 -e baby-cry -w 10 -n 2 ~/models/sound-detect
Restart=always
RestartSec=10[Install]
WantedBy=default.target
该服务将启动 ALSA 设备plughw:2,0上的麦克风监视器,如果在过去 10 秒内检测到至少 2 个 2 秒钟的正样本且先前状态为negative,则该服务将触发一个带有state=positive的baby-cry事件,如果在过去 10 秒内检测到不到 2 个正样本且先前状态为positive,则该服务将触发state=negative事件。然后,我们可以启动/启用服务:
systemctl --user start babymonitor.service
systemctl --user enable babymonitor.service
确认一旦婴儿开始哭闹,你的手机就会收到通知。如果你不这样做,你可以检查你应用到你的音频样本的标签,你的神经网络的结构和参数,或者样本长度/窗口/频带参数。
此外,考虑这是自动化的一个相对基本的例子——可以随意添加更多的自动化任务。例如,您可以使用[tts](https://platypush.readthedocs.io/en/latest/platypush/plugins/tts.html)插件向另一个 Platypush 设备(例如,在您的卧室或客厅)发送请求,大声说出婴儿在哭。您还可以扩展micmon_detect.py脚本,以便捕获的音频样本也可以通过 HTTP 传输——例如使用 Flask wrapper 和用于音频转换的ffmpeg。另一个有趣的用例是当婴儿开始/停止哭泣时将数据点发送到您的本地数据库(您可以参考我以前的文章如何使用 Platypush+PostgreSQL+Mosquitto+Grafana 来创建您灵活和自我管理的仪表板):这是一组有用的数据,用于跟踪您的婴儿何时睡觉、醒来或需要喂食。同样,监视我的孩子是开发micmon的主要动机,但完全相同的程序可以用来训练和使用模型来检测任何类型的声音。最后,你可以考虑使用一个好的电源组或一组锂电池,让你的声音监测器可以移动。
婴儿照相机
一旦你有了一个好的音频源和一种方法来检测一个积极的音频序列何时开始/停止,你可能想要添加一个视频源来关注你的宝宝。在我的第一次设置中,我在用于音频检测的 RaspberryPi 3 上安装了一个 PiCamera,我发现这个配置很不实用。一个 RaspberryPi 3 放在它的盒子里,附带一组电池和一个不知何故粘在顶部的相机可能会很笨重,如果你正在寻找一个可以轻松安装在支架或柔性臂上的轻型相机,你可以四处移动,随时随地关注你的宝宝。我最终选择了一个更小的 RaspberryPi Zero,配有 PiCamera 兼容的外壳和一个小的电源组。

我的婴儿监视器相机模块的第一个原型
像在另一个设备上一样,插入一个兼容 RaspberryPi 操作系统的 SD 卡。然后将兼容 RaspberryPi 的相机插入其插槽,确保相机模块在raspi-config中启用,并安装 Platypush 和 PiCamera 集成:
[sudo] pip3 install 'platypush[http,camera,picamera]'
然后在~/.config/platypush/config.yaml中添加摄像头配置:
camera.pi:
listen_port: 5001
您已经可以在 Platypush restart 上检查此配置,并通过 HTTP:
wget [http://raspberry-pi:8008/camera/pi/photo.jpg](http://turing:8008/camera/pi/photo.jpg)
或者在浏览器中打开视频源:
http://raspberry-pi:8008/camera/pi/video.mjpg
或者您可以创建一个钩子,当应用程序启动时,它通过 TCP/H264 开始流式传输摄像机输入:
mkdir -p ~/.config/platypush/scripts
cd ~/.config/platypush/scripts
touch __init__.py
vi camera.py
camera.py的内容:
您将能够在 VLC 等地播放提要:
vlc tcp/h264://raspberry-pi:5001
或者在你的手机上通过 VLC 应用程序或像 RPi 相机浏览器这样的应用程序。
音频监视器
最后一步是建立一个直接的麦克风流,从你的宝宝的 RaspberryPi 到你想要使用的客户端。当婴儿哭泣时,Tensorflow 模型可以很好地推动你,但我们都知道,机器学习模型并不是因为达到 100%的准确率而臭名昭著。有时你可能只是坐在另一个房间里,想听到宝宝房间里发生的事情。
我为此制作了一个名为 micstream 的工具/库——它实际上可以用于任何想要通过 HTTP/mp3 从麦克风设置音频馈送的情况。注意:如果您使用麦克风向 Tensorflow 模型提供音频,那么您将需要另一个麦克风进行流式传输。
只需克隆存储库并安装软件(唯一的依赖是系统上安装的ffmpeg可执行文件):
git clone [https://github.com/BlackLight/micstream.git](https://github.com/BlackLight/micstream/)
cd micstream
[sudo] python3 setup.py install
您可以通过micstream --help获得可用选项的完整列表。例如,如果您想在第三个音频输入设备(使用arecord -l获取完整列表)上设置流,在/baby.mp3端点上,监听端口 8088,比特率为 96 kbps,那么命令将是:
micstream -i plughw:3,0 -e '/baby.mp3' -b 96 -p 8088
你现在可以简单地从任何浏览器或音频播放器中打开[http://your-rpi:8088/baby.mp3](http://your-rpi:8088/baby.mp3),你将拥有来自婴儿监视器的实时音频。
创建您自己的单词云
学习使用 Python 构建一个非常简单的单词云,只需几行代码!
大家好!难道我们都没有看到如此有趣和新形式的单词云被展示出来,并想知道我们是否也可以生成这样的单词云。如果我告诉你一个不超过 20 行代码的 Python 程序**是可能的呢?让我们开始吧!
*
**
概观
在这个故事中,我将向你展示一个非常简单的代码,告诉你如何从任何文本数据中构建和生成一个非常简单的单词云。
数据
为了生成这个词云,我将使用一个数据集,该数据集最初是为了构建一个垃圾评论分类器而创建的。
文件'Youtube05-Shakira.csv'是由评论 ID、作者、日期、内容和类别等 5 列组成的数据集。“内容”和“类别”列用于建立机器学习模型,以将消息分类为垃圾消息。
为了生成我们的单词云,我将只在“内容”栏中使用单词。
步骤 1:导入库
任何 python 程序的第一步总是在导入库。对于这段代码,我们只需要三个* 库,其中两个应该已经安装在您的 Python 工作空间中了。在此程序之前,唯一需要额外安装的库是' wordcloud '库,可以使用' pip '命令轻松安装。*
*# Importing the Librariesfrom wordcloud import WordCloud, STOPWORDS
import pandas as pd
import matplotlib.pyplot as plt*
步骤 2:读取数据文件
下一步,我们将读取数据文件(。csv 文件)并存储在一个 熊猫数据帧 中。在处理大型数据集时,pandas 数据框总是更容易、更快速地使用。我们的单词云生成所需的列可以很容易地从 pandas 数据框中访问。
*# Read 'Youtube05-Shakira.csv' filedata = pd.read_csv(r"Youtube05-Shakira.csv", encoding ="latin-1")*
步骤 3:设置注释和停用词
在这一步中,我们为单词云生成初始化两个重要的字符串。
'comment _ words'是用于在单行文本中存储内容列的所有单词的字符串
‘stop _ words’用于存储所有英语中非常常用的单词,如‘the’,‘a’,‘an’,‘in’。这些单词将在稍后生成单词云时被过滤。
步骤 4:遍历数据文件
既然我们已经将数据文件存储到了 pandas dataframe 中,现在我们必须将“内容”列的每一行转换成一个很长的单行文本。
第一步是将 拆分 一行中的每个单词(一个注释有有限的单词数)并将其存储在一个变量中。separate = i.split()
拆分单词后,为了所有单词的同质性,我们使用.lower()函数将所有单词转换成小写的。**
最后,我们 连接 所有单词,并使用函数.join()将其存储到变量‘comment _ words’中。现在,变量‘comment _ words’comment _ words包含了生成我们的单词云所需的一个长文本中的所有单词。
**# Iterating through the .csv data file
for i in data.CONTENT:
i = str(i)
separate = i.split()
for j in range(len(separate)):
separate[j] = separate[j].lower()
comment_words += " ".join(separate)+" "**
步骤 5:创建单词云
在这一步,我们最终使用' WordCloud '函数生成单词云。在此,我们将使用两个变量'停止字和'注释字'。该代码不言自明,易于理解。
**# Creating the Word Cloud
final_wordcloud = WordCloud(width = 800, height = 800,
background_color ='black',
stopwords = stop_words,
min_font_size = 10).generate(comment_words)**
步骤 6:显示单词云
最后一步是显示我们刚刚使用上面的代码生成的单词云。'matplotlib . py plot'库用于显示 word cloud。看看下面生成的字云!
**# Displaying the WordCloud
plt.figure(figsize = (10, 10), facecolor = None)
plt.imshow(final_wordcloud)
plt.axis("off")
plt.tight_layout(pad = 0)
plt.show()**

生成的词云
万岁!您现在已经理解了如何使用 Python 和几行代码生成一个非常简单和基本的单词云。你现在可以以此为基础生成各种形状和类型的文字云!
我正在分享一个到我的 github 库的链接,在那里有 中的全部代码。ipynb 文件可供您使用!
** [## mk-gurucharan/Word-Cloud
这是从一个“.”构造单词云的代码。csv”文件。单词云(也称为标签云)是一种简单的可视化…
github.com](https://github.com/mk-gurucharan/Word-Cloud)
虽然,这并不是机器学习的一部分,这是人工智能的另一个重要领域(NLP)的最基本的运用之一。所以,继续尝试这个新领域的自然语言处理。到那时,快乐的机器学习!**
使用 Matplotlib 创建基本饼图

图片鸣谢:https://www . can va . com/design/DADyheAuwPg/cktbidgv 6 CW 60 nvqxcsw 4 w/edit?category=tACFakiSKJ8
如何使用饼图来描述您的数据。
饼图用于以突出每个数据点对整体的贡献(即 100%)的格式呈现分类数据。图表的形状是圆形的,就像一个饼图,每个数据点都以一定的百分比表示,同时从饼图中取一部分,形状像一个切片。它在饼图中的份额越大,数据点在饼图中所占的比例就越大。
如何在 Jupyter 笔记本中使用饼图
获取数据集
该数据集是从英格兰超级联赛网站上获得的,并收集了英格兰超级联赛中得分最高的前 15 名球员。然后,他们被操纵去找出英超球队是如何在这个表格中被代表的。


左图,英超 2019/20 赛季中期前五名球员。右边是前 15 名进球最多的球队中进球最多的前五支球队。
获得数据集后,下一步是导入数据可视化包进行分析。
导入数据可视化包
为构建饼图而导入的数据可视化包称为 Matplotlib,它是使用以下代码集导入的:
*## Import data visualization packages*
**import** **matplotlib.pyplot** **as** **plt**
%matplotlib inline
制作饼图
我们的目标是构建一个饼图,代表英超联赛中进球最多的前 15 支球队中进球最多的前 5 支球队。首先,将构建一个非常基本的饼图。饼图是使用以下代码制作的:
labels = df_score_2.index
colors = ['lightskyblue', 'red', 'blue', 'green', 'gold']
plt.pie(df_score_2['Stat'], labels= labels, colors=colors, startangle=90, autopct='**%.1f%%**')
plt.show()
标签= df_score_2.index 用于存储表格的索引,作为饼图的标签。标签是五个队的名字。颜色= ['亮天蓝色','红色','蓝色','绿色','金色'] 将用于代表饼状图中五支英超球队的每一片,作为他们的颜色。应使用 plt.pie(df_score_2['Stat'],labels= labels,colors=colors,startangle=90,autopct = '% . 1f % %%')创建饼图。 df_score_2['Stat'] 包含各队的数值,该数值应除以总数并乘以 100。它们切片的大小与它们的比例有关。标签=标签是饼图中每个扇区的标签。 colors = colors 用于高亮显示每个切片的颜色。startangle=90 代表饼图开始构建的角度。autopct = '% . 1f % %'用于格式化百分比在饼图上的显示方式。最后, plt.show() 用于显示饼图。

一个饼图,显示前 15 名进球最多的球队中进球最多的前 5 支球队。
增强饼图
上面的饼状图是一个草稿饼状图,可以通过添加更多代码来改进。假设利物浦将对阵托特纳姆热刺,两支球队都希望在视觉上更加突出。这可以使用下面编写的一组代码来完成:
*## for exploding the pie chart*
labels = df_score_2.index
colors = ['lightskyblue', 'red', 'blue', 'green', 'gold']
explode =(0,0.1,0,0.1,0)
plt.pie(df_score_2['Stat'], explode = explode,labels= labels, colors=colors, startangle=90, autopct='**%.1f%%**')
plt.show()
除了添加了新的一行代码 explode =(0,0.1,0,0.1,0) 之外,上面的代码没有任何变化。添加这行代码并明确表示括号中的第二个和第四个成员的值是 0.1,将会把利物浦和托特纳姆热刺队从馅饼中剔除。然后,一个新命令 explode = explode 被添加到 plt.pie 函数中。

一个改进的饼状图显示了前 15 名进球最多的球队中进球最多的前 5 支球队,剔除了利物浦和热刺。
增强饼图 II
使用下面的代码,可以通过包含更多细节的标题和添加阴影使饼图看起来更坚实来进一步改进饼图。
*## Adding a title to the pie chart and a shadow to the chart*
labels = df_score_2.index
colors = ['lightskyblue', 'red', 'blue', 'green', 'gold']
explode =(0,0.1,0,0.1,0)
plt.pie(df_score_2['Stat'], explode = explode,labels= labels, colors=colors, startangle=90, autopct='**%.1f%%**', shadow = **True**) plt.title("Top five teams with the most goals among the top 15 highest goal scorers **\n**in the premier league 2019/20 mid-season", fontsize = 18)
plt.show()
函数 plt.pie 中增加了 shadow = True 命令,使饼状图看起来更优雅。 plt.title("英超 2019/20 赛季中期前 15 名进球最多的球队\ n" fontsize = 18)代码也被用来给饼状图添加标题。

一个改进的饼状图,显示了前 15 名进球最多的球队中进球最多的前 5 支球队,其中主要剔除了利物浦和热刺。
增强饼图 III
可以对饼图进行更多的改进,使其更具结构性和可展示性。可以添加图例,可以放大饼图,可以增强图片的结构。
*## Adding a legend to the chart and increasing its size*
labels = df_score_2.index
colors = [‘lightskyblue’, ‘red’, ‘blue’, ‘green’, ‘gold’]
explode =(0,0.1,0,0.1,0)
fig, ax1 = plt.subplots(figsize = (24,12))
ax1.pie(df_score_2[‘Stat’], explode = explode, colors=colors, startangle=90, autopct=’**%.1f%%**’, shadow = **True**)
plt.title(“Top five teams with the most goals among the top 15 highest goal scorers **\n**in the premier league 2019/20 mid-season”, fontsize = 24)
ax1.legend(labels, loc = “upper right”)
plt.tight_layout()
plt.show()
新增加的内容包括添加 fig,ax1 = plt.subplots(figsize = (24,12)) 这是在使饼状图的绘图功能分配给 ax1 时用于放大饼状图的代码。**PLT . pie变成 ax1.pie. 然后用 ax1.legend(labels,loc = "upper right") 给饼状图添加图例,用标签作为图例,图例位于图的右上角。 plt.tight_layout() 用于将饼状图更好的固定到图中。

一个改进的饼状图,显示了前 15 名进球最多的球队中进球最多的前 5 支球队,其中主要剔除了利物浦和热刺。
上面的饼状图是饼状图漂亮的表现形式,也是如何将饼状图放到饼状图中的一个例子。
饼图在对合计总值的数据进行分类时非常有用,可以显示每个类别在饼图中所占的比重。例如,大学校园中的种族代表或街区中的车辆品牌所有权。
用 Python 创建漂亮的 Web API
使用可持续的编码实践,用 Python、Flask 和 MongoDB 创建一个完整的 web API。



Flask 和 MongoDB
创建一个带有数据库后台的网站或 API 是一个很棒的编程项目,但是它可能很难开始,因为有太多的概念要处理。本指南旨在帮助您从头到尾使用 Python Flask 和 MongoDB 构建您的第一个(或第五个)API。
开始之前:本指南是针对初学者/中级水平的。我希望了解一点 python 知识和面向对象编程的基础知识。至于我自己,我的背景是物理、数学和机器学习——但是网络方面的东西总是让人望而生畏。很容易找到每一部分的单独教程,但本教程更多的是将所有部分放在一起,以制作可持续的代码。希望这份指南能帮你减轻压力。
一旦你理解了这些步骤以及每个部分是如何组合在一起的,我强烈建议你更详细地了解每个组件。另一个建议是:试着事后自己从头开始重建整个系统。
这里是我们将要研究的所有技术和工具的分类(不要担心这个列表的大小,大多数都不太有威胁性!):
什么是 Web API?
- 带示例的 Web APIs 介绍
MongoDB:
- MongoDB 简介
- 安装和启动服务器
- 添加一些数据并运行测试查询
烧瓶:
- 烧瓶介绍
- Flask-MongoEngine { 用于以面向对象的方式处理 MongoDB
- 用于加密密码 }的 Flask-Bcrypt {
- Flask-RESTful { 用于构建 REST API}
- flask-JWT-扩展{ 用于认证和授权
邮递员:
- 邮递员介绍
- 采样数据并使用 GET、PUT、POST、DELETE 请求
托管您的 API:
- 在本地计算机上运行和测试
- 使用 gunicorn 在 Heroku 上公开托管 API
- (将来可能会添加在 Google 云平台上托管的可选指南)
好了,我们开始吧!
抓取 GitHub 模板代码:
*git clone -b template [https://github.com/jrbarhydt/FlaskWebAPI.git](https://github.com/jrbarhydt/FlaskWebAPI.git)*
或者自己动手建造:
*│
│ app.py
│ Procfile
│ requirements.txt
│ runtime.txt
│
├───api
│ authentication.py
│ meal.py
│ routes.py
│ user.py
│ __init__.py
│
├───models
│ meals.py
│ users.py
│ __init__.py
│
├───resources
│ meal_data.csv
│ user_data.csv
│
└───tools
load_data.py
__init__.py*
什么是 Web API?
Web API(应用程序编程接口)允许您通过 Web 提供数据,通常是 JSON 或 XML 格式。通常,这是通过公开端点来发出请求来实现的。

一个例子是口袋妖怪 API(https://pokeapi.co/),它可以让你访问口袋妖怪数据库。试试下面的链接,获取你想知道的关于杰尼龟的所有数据!
https://pokeapi.co/api/v2/pokemon/squirtle
你可能会注意到有一个巨大的文本墙返回!这就是为什么我喜欢使用 Chrome 的 JSON Viewer 扩展,以更可读的格式查看数据,如图所示。
让我们分解杰尼龟链接,了解一点关于端点(或者我们在 Flask 中称之为“路由”)的知识

入口点(左框)和端点(右框)
按照惯例,一个 API 将有一个入口点。这就像文件资源管理器中的根文件夹。可以有任意数量的端点(从现在开始我将称之为‘路由’)。)
根据给定的路由,数据可以以不同的形式传递。尝试导航到/pokemon 路径,您将获得所有 pokemon 的数据,而不仅仅是杰尼龟的数据。
对于我们的 API,我们将创建一个餐馆数据库,用户可以在其中注册、登录、保存他们的详细信息,并保存他们最喜欢的饭菜的列表。一些用户将被允许执行管理任务,如删除用户或访问任何用户的膳食列表。
MongoDB { () }
MongoDB 简介:
为您的项目选择正确的数据库类型非常重要。传统的 SQL 数据库将信息存储在表中。这与 noSQL 数据库形成对比。
MongoDB 是一个 noSQL 数据库,以 JSON 格式存储数据。与表相反,JSON 形成了一个树形数据结构。单个记录被称为“文档”
(我会推荐盯着上面的口袋妖怪 JSON 数据,直到你确信那是一棵树而不是一张桌子。)
安装并启动服务器:
你可以在 https://www.mongodb.com/download-center/community获得 MongoDB 的免费版本**

默认安装选项
目前默认设置是好的。Compass 是可选的,我们不会在本教程中使用它。无论您在哪里安装 MongoDB 和您的数据库,一定要记住位置。
启动服务器:C:\ Program Files \ MongoDB \ Server \ 4.2 \ bin \ mongod . exe**
让您的服务器在后台运行,您现在可以从 mongo shell 访问您的数据库,或者我们将在后面看到,也可以从 python 访问。这是一个不安全的服务器,稍后我们将添加授权。
启动 Mongo Shell:C:\ Program Files \ MongoDB \ Server \ 4.2 \ bin \ Mongo . exe**
我建议你在玩https://docs.mongodb.com/manual/reference/mongo-shell/的时候看看 MongoDB 文档
让我们在数据库中插入一些记录(文件)。(您可以复制这些内容,然后使用右键将它们粘贴到 mongo 命令 shell 中。)
**use test_dbdb.meals.insert({"name": "Mystery Pie", "description": "Not even the baker knows what's inside..."})db.meals.insert({"name": "Apple Pie", "description": "A delicious, home-made apple pie. Best served on a window sill in the summer."})**
“use”将选择一个 db(或创建一个),您可能会注意到我们插入的记录是 JSON 格式的。此外,如果集合不存在,mongo 会自动创建它。以上,我们的集合叫做‘饭’。
通过将以下内容粘贴到 mongo 来验证一切正常。
**show databasesshow collectionsdb.meals.find()db.meals.find({"name": "Apple Pie"})**
使用数据库。

您添加的每个项目都有一个唯一的 ObjectId。这在以后引用其他集合(比如用户)中的项目时会很方便。
尝试制作数据库、集合和文档。你现在已经有了运行数据库的非常** 基础知识。**
为了安全起见,请为您的数据库设置管理员凭据。(也许不要让你的密码成为“密码”)
**use admin
db.createUser(
{
user: "admin",
pwd: "password",
roles: [ { role: "userAdminAnyDatabase", db: "admin" }, "readWriteAnyDatabase" ]
}
)
db.adminCommand( { shutdown: 1 } )**
最后一个命令将关闭我们的服务器。要在启用身份验证的情况下启动服务器,请改为从终端运行。
**mongod --auth**
运行此服务器时,如果不先进行身份验证,您将无法执行任何操作。您可以通过重新启动 mongo.exe 并尝试访问一些数据来测试这一点。在 mongo shell 中输入以下内容以登录并获得访问权限。
**use admin
db.auth("admin", "password")**
我们现在有了安全的数据库服务器,所以是时候开始构建 API 了。
烧瓶\_
Flask 是一个轻量级的 web 框架。使用 Flask,您可以挑选您的站点需要的组件和扩展。我喜欢这个方面,因为模块化的本质允许你构建一切,没有太多的混乱。
我们将使用的主要 Flask 扩展是 Flask MongoEngine 和 Flask RESTful。第一个将让我们为我们的数据构建类作为模板,而后者是为构建 API 而设计的,并使过程更简单。
此外,我们将使用 JWT 扩展和 BCrypt,但我将在后面介绍它们。
现在,是编码时间了…
创建一个干净的虚拟环境,并获得烧瓶。
如果你不熟悉虚拟环境,这不会伤害我的感情,但你绝对应该看看https://docs.python.org/3/tutorial/venv.html
**pip install Flask**
现在,在深入研究之前,我想在这里对我的编码方法做一些评论。以下是我收录的一些东西:
- 我已经记录了每个部分。如果我不得不在几个月后回到这段代码来添加新特性、修复某些东西,或者甚至是重温一些我不得不解决的问题,这可能会非常有帮助。
- 我有一个默认配置,这对测试很有用。在生产环境中,您可以轻松地将非测试信息传递到函数中。(如果不使用配置调用函数,将使用默认值)
- 我使用 Python 的类型提示来跟踪参数和返回值类型。
- 我在一个函数中创建并返回了应用程序。这对测试和可伸缩性也有好处。例如,您可以使用不同的配置运行 get_flask_app 两次。
- 我添加了 main 入口点,所以如果我照原样执行这个脚本,它将在调试模式下启动。稍后我将介绍 gunicorn 的发布。
粘贴以下代码。
- app.py
您现在可以运行 app.py,并且您将托管一个 Flask 服务器。不过,它还不能做任何事情。

在调试模式下运行 Flask 服务器:使用 PyCharm Community Edition
烧瓶-MongoEngine:
获取 Flask-MongoEngine,以及用于密码加密的 BCrypt。
**pip install flask-mongoengine
pip install flask-bcrypt**
查看文档了解更多细节和实现示例。http://docs . mongoengine . org/projects/flask-mongoengine/en/latest/
Flask-MongoEngine 还附带了 MongoEngine 和 PyMongo。您可能会发现这些库本身很有趣。也看看他们的文件!http://docs.mongoengine.org/
https://pymongo.readthedocs.io/en/stable/
我们不会使用 PyMongo,但是如果你非常习惯使用 mongo shell,你可能会喜欢这个包。它使用的 python 命令与您在 mongo shell 中输入的命令几乎相同!
我们将为用户创建一个类模型,为用餐创建另一个类模型。这些将存在于模型文件夹中。将下面的膳食类与我们通过 shell 放入 mongo 的条目进行比较。如您所见,MongoEngine 更加面向对象。
- models/meals.py(无文档)
**from mongoengine import Document, StringField, FloatField
class Meals(Document):
name = StringField(required=True)
description = StringField()
price = FloatField()
image_url = StringField()**
在做用户之前,我会补充一些文档。我想展示原始代码和文档完整的版本之间的区别。在示例部分中,包含了可以直接运行或使用 doctest 运行的代码。我喜欢添加 doctest 风格的注释,因为它们既是一个测试,也是一个使用示例。
**:: Execute a doctest in the terminal
python -m doctest api/meals.py**
文档中所有以 > > > 开头的代码都将由 doctest 运行。
- models/meals.py(带文档)
Users 类稍微复杂一些。有一个用于确定访问级别的字段,一个用于验证电话号码的字段,Users 类覆盖了 Document.save()方法,因此我们可以在保存到数据库之前生成一个密码散列。这样,如果我们的数据库遭到破坏,攻击者将无法获得实际的密码。
**这是关于 Flask-BCrypt 的文件。
了解更多慢哈希和盐,在这里!【https://crackstation.net/hashing-security.htm】T5
**
- 模型/用户. py
恭喜,现在 MongoEngine 模型完成了!接下来,我们将为 API 构建接口。
烧瓶-RESTful
**pip install flask-restful**
Flask-RESTful 库需要一个非常类似 MongoEngine 的设置,我们将为每个 API 交互创建一个类。这些类被称为资源。在 Flask 中,将资源连接到端点被称为路由。这就是我们所说的路线。
我们的 API 将有几条路线。一个用于身份验证(注册和登录),另一个用于用户(获取、上传或删除用户数据),另一个用于用餐(获取、上传或发布)。
我们最终将需要使用 web 令牌来访问所有数据,但是首先我们将添加进行第一次 API 调用所必需的基础知识。
点击这里了解更多关于 JSON Web 令牌的信息
https://jwt.io/
现在,要获得我们的第一个 API 调用:
- api/meal.py
**# flask packages
from flask import jsonify
from flask_restful import Resource
# mongo-engine models
from models.meals import Meals
class MealsApi(Resource):
def get(self):
output = Meals.objects()
return jsonify({'result': output})**
当我们向正确的路由发出 get 请求时,这个类的 GET()方法将被调用。这个方法返回 Meals 中的所有对象(我们目前有 2 个),并将它们转换成 JSON 响应。
所以,现在我们需要指定正确的路径来访问它。将以下内容添加到路线中。
- api/routes.py
**from api.meal import MealsApi
def create_routes(api):
api.add_resource(MealsApi, '/meal/')**
在这里,我们添加了刚刚创建的 MealsApi 资源,并将其命名为“/meal/”端点。因此,现在我们有了一个完整的路线,就像使用 PokeAPI 一样,我们可以开始提供数据!在设置 app.py 之后。
更新导入部分以获取 app.py 中的必要模块
**# flask packages
from flask import Flask, app
from flask_restful import Api
from flask_mongoengine import MongoEngine# local packages
from api.routes import create_routes**
在 app.py 中的 get_flask_app()的末尾添加以下行,以便设置 RESTful API 和 MongoEngine。
**# init api and routes
api = Api(app=flask_app)
create_routes(api=api)# init mongoengine
db = MongoEngine(app=flask_app)return flask_app**
试试看。运行 app.py,您将看到显示的默认 URL。你可以导航到http://127 . 0 . 0 . 1:5000/meal/获得 MongoDB 数据库中所有餐食的打印输出。(你还需要让 mongod.exe 来运行这个功能)

太好了。现在,我们将通过执行相同的步骤来继续其余的资源和路线。我还会添加文档。
身份验证允许用户在访问数据之前登录。我们有两条路线,一条是唱歌的路线,另一条是登录的路线。SignUpApi 类与对用户模型的 POST 请求相同,只是它不需要预先认证(因为用户还没有注册)。
关于这些类的编码有几点注意事项:
- post()方法是静态的,因为该类没有特殊的上下文,比如需要 JSON Web 令牌。
- get、post、put 和 delete 返回类型是 Response,这是 Flask 从 Werkzeug 继承的一个类,但是不需要理解底层机制。它只是处理 HTTP 通信的东西。当您将字典对象传递到 Flask.jsonify 时,flask 会负责这一点。
- 如果用户( 数据)中的星号对您来说很陌生,不要担心,这只是使用字典将参数传递到类或方法的一种简洁方式。
看看字典拆包了解更多。
- LoginApi 检查给定的密码是否匹配,如果匹配,则创建 web 令牌。这些令牌允许用户继续使用 API,而不需要为每个请求登录。生成了刷新令牌,但在本教程中没有使用。这将允许用户在令牌过期后继续他们的会话。
点击此处了解有关使用令牌保护数据安全的更多信息【https://auth0.com/docs/tokens/concepts/access-tokens T2
这是完整的验证码。
- API/认证. py
错误消息应该是不言自明的。
- api/errors.py
关于两餐 api 资源有两件事要提一下。首先,你会注意到一些方法现在有了参数。这是由 routes.py 处理的,它将阻止来自端点的参数。更多信息请见下面的路线部分。其次,您会注意到在一些方法之前有@jwt_required 装饰符。这一行允许您强制使用 web 令牌来访问数据。
**如果你过去没有用过装饰师,我建议你多学一点。它们可以非常方便地为一个方法快速添加功能。【https://realpython.com/primer-on-python-decorators/】T5
**
下面是代码。
- api/meal.py
routes.py 的一个新增功能超级重要。您会注意到一个参数在端点内部传递。参数通过将名称放在尖括号内来表示。Flask RESTful 将识别这些括号,并将值传递给 get()、post()、put()或 delete()方法。
- api/routes.py
user.py 中的代码与上面的 meal.py 中使用的代码非常相似。
- api/user.py
最后,不要忘记更新 app.py。除了添加新的导入和初始化 JWT,我们还必须在默认配置中添加一个 jwt 秘钥。显然,您不希望您的产品代码使用这个键,但是就像默认的用户名和密码一样,这些只是为了测试而指定的。在生产设置中,您可以将配置文件保存在其他地方,并将其传递给 get_flask_app()方法。app.py 的最终版本如下。
- app.py
不要忘记添加 flask-jwt-extended
**pip install flask-jwt-extended**
就是这样。现在 API 已经完成了。嗯,算是吧。我们没有一个好的方法来测试它的每一个方面(比如创建一个新用户,等等。)虽然这可以使用请求库在 python 中直接完成,但我将使用 Postman。我发现这是测试 API 的一个很好的方法。
邮递员(/)
我不会解释 Postman 带给你的所有乐趣,我会带你一步一步地注册、登录和添加数据。这将让你开始,但里面有很多伟大的功能。
下载邮递员在postman.com/downloads

您可以在上面看到 get 请求的结果。这与我们之前在 mongod.exe 和 app.py 都运行的情况下,在网络浏览器中输入“http://127.0.0.1:5000/meal”得到的结果相同。
- 如果你再试一次,就会失败!你能猜到原因吗?向下滚动寻找答案,但如果你能自己想出答案就加分了。

给你个提示…
我们没有网络令牌!
要获得一个,我们需要登录。为了登录,我们需要注册。
好,那我们报名吧。设置一个 POST 请求,并将 url 设置为http://127 . 0 . 0 . 1:5000/authentic ation/sign up/并添加一个主体,类型为 raw JSON 。在正文中输入以下内容,然后单击 Send。
**{
"email": "[test@not-a-fake-email.com](mailto:test@not-a-fake-email.com)",
"password": "hunter2",
"access": {
"admin": "True"
},
"name": "testy buddy",
"phone": "555-555-5432"
}**
该响应包括唯一的 user_id。这对需要它的路线也有帮助。

现在,我们将登录以获取我们的 web 令牌。有趣的事实是,您唯一的 user_id 也将被编码在 web 令牌中,因此没有必要记住它。您可以在 MealApi 类的 meal.py 中看到 get_jwt_identity()方法。
如果您喜欢冒险,您甚至可以更改我们路线中的“/user/ <user_id>”端点。因为我们可以使用 get_jwt_identity()从 web 令牌中获取这些信息,所以我们可以使用单个端点来获取单个用户。也许可以尝试“user/get_user/”并在 MealApi 中放弃 user_id 参数。</user_id>
为了登录,我们将通过登录路径发布电子邮件和密码。
**{
"email": "[test@not-a-fake-email.com](mailto:test@not-a-fake-email.com)",
"password": "hunter2"
}**
您可以看到 API 令牌被成功返回。

我们可以复制访问令牌并将其粘贴到授权头中。
再次尝试从 餐端点 访问一个 GET 请求,但这次将 access_token 放入授权标签的 Token 字段,选择无记名令牌作为类型。看看你,跟随着一堆网络术语!

通过内部 Web API 访问 MongoDB 数据
现在,您可以添加自己的数据来填充数据库。或者您可以使用 resources/meal_data.tsv 和 resources/user_data.tsv,它们包含许多条目。我建议您编写自己的脚本来完成这项工作,但是如果您只想输入一些测试数据,我将包括 tools/load_data.load_all()。
下面是数据:
- resources/meal_data.csv
- 资源/用户数据. csv
以下是我制作的用于将数据加载到 MongoDB 的工具:
-
工具/get_random_document.py
-
工具/load_data.py
-
tools/mongo_loader.py
托管您的 API
到目前为止,一切都在本地运行。为了让任何人通过互联网访问您的 API,您必须在某个公共可访问的地方托管一个 web 服务器和数据库服务器。有许多方法可以做到这一点,但是我将介绍使用 Heroku 进行部署。
Heroku [K]
一个简单的方法是用 Heroku 实现主机和 API。Heroku 非常简单,因为它允许您拥有一个专门针对 web 服务器的 git 存储库。
首先,在https://www.heroku.com/上建立一个免费账户,登录后,从主菜单中选择“创建新应用”。您将在

首先,为了让 Heroku 知道如何运行您的应用程序,它将在您的主项目目录中查找三个文件。
- Procfile:这是一个 shell 脚本命令,Heroku 将首先运行它。在我们的例子中,它启动 gunicorn 的方式与我们之前在本地启动它的方式相同。
**web: gunicorn 'app:get_flask_app()'**
- requirements.txt:这包含了我们使用的所有 python 包。你可以通过运行 pip freeze 来获得这个列表。我会把我的列表粘贴在下面,你的可能会略有不同。
**aniso8601==8.0.0
bcrypt==3.1.7
cffi==1.14.0
click==7.1.1
Flask==1.1.2
Flask-Bcrypt==0.7.1
Flask-JWT-Extended==3.24.1
flask-mongoengine==0.9.5
Flask-RESTful==0.3.8
Flask-WTF==0.14.3
gunicorn==20.0.4
itsdangerous==1.1.0
Jinja2==2.11.2
MarkupSafe==1.1.1
mongoengine==0.19.1
pycparser==2.20
PyJWT==1.7.1
pymongo==3.10.1
pytz==2019.3
six==1.14.0
Werkzeug==1.0.1
WTForms==2.2.1**
- 这告诉 Heroku 我们使用的是哪个版本的 python
**python-3.7.6**
最后,这里是 Heroku 网页上的选项卡列表,您将配置这些选项卡来启动和运行您的 API。
- ****资源:在附加组件中,搜索 mLab MongoDB 并将其添加到你的应用中。你可以选择免费版本。你将不得不为此输入你的支付细节,但只要你坚持使用免费版本,你就不会被收费。
- ****部署:连接你的 GitHub 账号,选择包含你所有 API 项目文件的 GitHub 项目。您可以让 Heroku 从主分支自动部署。
如果不想使用 GitHub 账号,也可以选择用 Heroku CLI 部署。如果你选择这种方法,Heroku 网站上有安装应用程序的说明。
- ****设置:在配置变量下,点击显示配置变量,得到重要变量列表。这里需要两个变量:URI 和 JWT 密钥。秘密密钥是私有的,由您决定,因为它允许对 web 令牌进行加密/解密。
好了,应该就这些了。您可以在 Activity 选项卡中查看构建是否成功,或者读取构建日志等。
现在,使用 Postman 和以前一样尝试,除了这次使用新的公共 API URL 和端点。

向 Postman 注册公共 Web API

使用 Postman 登录公共 Web API
对于另一个挑战,看看你能否将你的数据加载到公共网站上。你可以使用 load_data.py,但是你必须使用 Heroku 给你的 MONGODB_URI 和新的 JWT_SECRET_KEY。下面是一个示例脚本。
**from tools.load_data import load_all
MONGODB_URI = 'YOUR-URI-HERE'
JWT_SECRET_KEY = 'YOUR-KEY-HERE'
new_config = {'MONGODB_SETTINGS': {'host': MONGODB_URI, 'retryWrites': False},
'JWT_SECRET_KEY': JWT_SECRET_KEY}
load_all(new_config)**
延伸阅读:
- DataCamp 有大量与数据相关的教程。你也可以在 MongoDB 上进行更多的练习。
** [## Python 中使用 MongoDB 进行数据科学的介绍
这一章是关于获得诺贝尔奖数据结构的鸟瞰图。您将关联 MongoDB 文档…
www.datacamp.com](https://www.datacamp.com/courses/introduction-to-using-mongodb-for-data-science-with-python)
- RealPython 有很多学习 Python 的好材料。我特别喜欢他们的烧瓶教程。
Flask 是一个流行的 Python web 框架,这意味着它是一个第三方 Python 库,用于开发 web…
realpython.com](https://realpython.com/tutorials/flask/)
参考资料:
为了生成合成数据,我使用了这些:
Lorem Ipsum 文本生成器
pypi.org](https://pypi.org/project/loremipsum/) [## 在假名生成器中获得一个全新的身份
4808 Parker DriveBeachwood,OH 44122 邮箱 BryanDAdams @ teleworm.us 网站 partprocure.com 浏览器用户代理…
www.fakenamegenerator.com](https://www.fakenamegenerator.com/)
以下是我在文章中提到的一些好东西。
一个开放的用于神奇宝贝数据的 RESTful API
pokeapi.co](https://pokeapi.co/) [## JSON 查看器
你的眼睛所见过的最漂亮的可定制的 JSON/JSONP 荧光笔。开源于…
chrome.google.com](https://chrome.google.com/webstore/detail/json-viewer/gbmdgpbipfallnflgajpaliibnhdgobh?hl=en-US) [## 12.虚拟环境和包- Python 3.8.2 文档
Python 应用程序通常会使用不属于标准库的包和模块。应用程序…
docs.python.org](https://docs.python.org/3/tutorial/venv.html) [## mongo Shell 快速参考- MongoDB 手册
编辑描述
docs.mongodb.com](https://docs.mongodb.com/manual/reference/mongo-shell/) [## Flask-MongoEngine-Flask-MongoEngine 0 . 9 . 5 文档
提供与 MongoEngine 集成的 Flask 扩展。有关 MongoEngine 的更多信息,请查看…
docs.mongoengine.org](http://docs.mongoengine.org/projects/flask-mongoengine/en/latest/) [## 安全加盐密码散列法——如何正确使用
在用户的哈希列表中搜索哈希(apple)...:匹配[alice3,0bob0,charles8]在…中搜索哈希(蓝莓)
crackstation.net](https://crackstation.net/hashing-security.htm)**
用 Doc2Vec 创建啤酒推荐器
我是如何培训和评估基于内容的啤酒厂旅行者推荐系统的

在这篇文章中,我将讲述我是如何培训和评估我的酿酒厂推荐人的。部署模型可以在这里找到:【https://tinyurl.com/beer30rec】T4。Beer30 是一款基于内容的啤酒厂旅行者推荐产品!如果你有兴趣,这里有一个项目回购的链接。
我尝试用 PySpark 和 Surprise 创建一个协作过滤器,遗憾的是结果并不是很好(这里是我最初的 EDA 查看数据集的数字评级信息,但它与本部分不太相关)。该计划是让一名新用户对他们尝试过的一些啤酒进行评级,然后该模型会将他们与类似的用户进行匹配,并根据匹配的用户口味进行推荐。某些啤酒被如此多的用户评为如此之高,以至于最终严重偏离了模型,它们实际上总是被推荐。我试着做了一个新用户,并给许多评级最高/炒作桶陈年黑啤酒都打了 1 分(5 分制)。然后,当查询推荐时,该模型仍然会对桶装陈酿黑啤酒进行高度排序!所以真的,它根本不起作用。
我决定把重点放在文本评论上,因为它们充满了丰富的描述性词语。通过只看文本评论,并在啤酒中进行比较,我开始转向训练一个基于内容的推荐者。在研究潜在模型时,我突然意识到 Doc2Vec 可能会工作得很好——我可以将每种独特的啤酒标记为独特的文档。模型创建的超维空间将是啤酒的映射!
现在让我们开始吧!

图片来自 Pixabay 的 Ryan McGuire
查看文本评论
我想展示一些文本数据中丰富的描述性词汇的例子。以下是一些摘录:
On-tap at Local Option. A - Pours black, tan head, thin ring, no lace or cap. S - Nice level of roast, chocolate, caramel, and coffee. There's a nice chocolate roasty sweetness that keeps me coming back for me. T - Dark chocolate, roast, coffee beans, oak, burnt sugars. The chocolate and roast once again have me in love with this one. The coffee notes are nice as well with a touch of vanilla. M - Medium body, good carbonation, smooth, rich, creamy finish. D - A really nice porter...I had to get another after my initial pour. Would def have again if it's floating around town...would probably even seek out just to have it again.
_______________________________________________________________
pours a hazy, almost cloudy, autumn gold. Apparently unfiltered. Rich, off-white head settles to a tight, solid cap of foam. Aroma is straight up Belgian yeast, with the overripe fruit esters of banana and melon skin, and a hint of spice. Taste has a nice balance of sweet honey malts and tangy, bubblegum-y yeast. Floral, lemony hops come in strong, with a surprising cilantro-like soapy bitterness. Any sweetness begins to yield to dry, crackery malts and tart apple. All that's missing is a nice wedge of brie. Bitterness in the finish lingers a bit long for my taste and is my only real complaint. Nice rustic quality to it that is suggestive of a farmhouse ale or biere de garde. Terrific, weighty mouthfeel for a regular BPA without become heavy or cloying. A brisk carbonation helps in that regard, as does the dry finish. A bit too bitter for the style perhaps, but pair it with some rich cheese, a baguette and some fig preserves and you have a great picnic.
_______________________________________________________________
Pours a creamy opaque light straw yellow with a whispy frothy white head. Nose is of citrus skin and light pine. Taste is a thing of beauty! A nice citrus punch in the mouth. Both peeland zest as well as juice of oranges, grapefruit and lemon. Nice malt backbone although minimal presence, you know its there because the hoppyness of this beer is perfectly balanced. Meadium creamy body. Smooth to drink. Finishes with with a Nice pungent citrus bitterness that leaves you craving the next sip to start the process over again. By far my favorite Treehouse brew of the 4 or 5 I’ve had
这篇文章肯定有一些有趣的细微差别。例如,在第二个例子中:“可能对风格来说有点太苦了”——模型将重点放在“苦”上,但在这个例子中,它不是一个有益的特性。我想探索的是情感分析。我最初的想法是平均每种啤酒的情绪,然后将其纳入推荐。
你会注意到的一件事是,人们确实经常提到啤酒风格。我努力把它们包括进来或者指定为停用词(被删除),决定把它们留在里面,因为有很多不同的方式来列出一种风格。我宁愿包括所有的,然后只删除其中的一部分。
准备数据
将 beers 和 reviews csv 文件加载到 Panda 的 DataFrame 中,然后用自定义函数(来自 my functions.py 文件)处理它们。我们还将生成一组停用词!这些包括这个用例的一些自定义单词:关于倒啤酒的单词,他们使用的是哪种杯子(郁金香、斯尼夫特、品脱、玻璃杯)以及与啤酒如何储存有关的单词(罐、瓶、盖、软木塞)。它还删除了评论少于 10 条的啤酒,以及一贯评价啤酒过低或过高的用户。最后,它删除了奇怪的 unicode 字符和没有文本的评论。你最终会得到不到 200 万条评论。
reviews = pd.read_csv('reviews.csv')
beers = pd.read_csv('beers.csv')cleaned_reviews_df = functions.preprocess_reviews(reviews, beers)my_stop_words = functions.make_stop_words()
在 Doc2Vec 中,每个文档都有一个标签。在这种情况下,每个啤酒评论都是一个文档,我们将用啤酒的 beer_id 标记每个评论。该模型将建立一个空间,其中每种啤酒都有自己的向量,这些向量基于该啤酒的所有评论集合中的单词。现在,我们将做一些自然语言处理预处理,然后在每个评论中提取所有单词。
# initiate a Lancaster Stemmer, and stem beer reviews while tagging them for Doc2Vecls = LancasterStemmer()tagged_stem_docs = functions.stem_tag_docs(cleaned_reviews_df,\ my_stop_words)
这最后一步需要一些时间,因为它要遍历近 200 万条评论中的每一个词。接下来,我们将实例化一个 Doc2Vec 对象,并让它从文本语料库中的所有唯一单词构建一个词汇表。然后我们将训练模型。这些步骤在我的笔记本电脑上花费了一个多小时,但我也在我的最终模型中训练了 20 个纪元(下面的代码只有 1 个)。
# Instantiate a Doc2Vec modelmodel = Doc2Vec(dm=0, dbow_words=1, min_count=4, negative=3,
hs=0, sample=1e-4, window=5, size=100, workers=8)# Build the vocab from the tagged documents
model.build_vocab(tagged_stem_docs, progress_per = 100)# Train the model from the tagged documents
model.train(tagged_stem_docs, total_examples=model.corpus_count, epochs=1)
模型训练的时候去散步什么的吧!之后,您可以使用我的位置过滤器开始探索酿酒厂!下面的代码是一个例子,展示了如何用关键词或者特定的啤酒进行搜索。
该模型还将 vocab 单词映射到与文档相同的空间中,因此您可以匹配哪些啤酒最接近某个单词。如果你搜索一种特定的啤酒,这是一种啤酒与啤酒的比较。
# Search based on a keyword
vec = model['bourbon']
similar_beers = model.docvecs.most_similar([vec], topn=5000)# Search based on a specific beer, where the string is the beer_id
similar_beers = model.docvecs.most_similar('55401')# load lookup dictionary pickle file
file = open('lookup_dict.pickle', 'rb')
lookup_dict = pickle.load(file)
file.close# You can try changing the location data, if you'd like. I'm going with my hometown for these examples
functions.location_filter2(similar_beers, lookup_dict, 'WA', 'Seattle', 3)# output of the keyword search, keys are the unique brewery ID. Values are a tuple that contain the Brewery Name, Beer ID, and Beer Name
{20680: ('Fremont Brewing Company', '140119', 'Bourbon Barrel Aged Dark Star'),
17005: ('Two Beers Brewing Co.', '105241', 'Overhang (Alta Series)'),
29693: ("Reuben's Brews", '90460', 'Imperial Stout - Bourbon Barrel-Aged')}
万岁!我们做到了!
可视化模型
评估这样的模型很有挑战性,因为没有定量的方法来这样做。但是可视化模型的一个很好的方法是使用一种叫做 t-SNE(t-分布式随机邻居嵌入)的技术。它是一种降维形式,类似于主成分分析。
让我们导入必要的包。
from sklearn.manifold import TSNE
import matplotlib.pyplot as plt
from functions import make_tsne_subset
下面的代码将创建一个包含 22,514 个元素的数组(X )(每种啤酒一个元素)。然后,我们用文档向量拟合/转换 t-SNE 对象,并将输出数组转换为数据帧,以便用 Matplotlib 绘图。
# doc_tags is just a list of every unique document tag/beer_id
doc_tags = list(model.docvecs.doctags.keys())# get the vector for each doc_tag
X = model[doc_tags]# Fit and transform a t-SNE object with the vector data for dimensionality reductiontsne = TSNE(n_components=2)
X_tsne = tsne.fit_transform(X)
df = pd.DataFrame(X_tsne, index=doc_tags, columns=['x', 'y'])# create a scatterplot of the resulting 2-dimensional data
plt.scatter(df['x'], df['y'], s=0.4, alpha=0.4)

高维 beer 向量的二维 t-SNE 图
我们看到这个模型有一些非常大的分离!啤酒风格总是有一点重叠,从图中也可以明显看出这一点。但是有非常明显的分类,我们很快就会看到啤酒风格的巨大差异。
模型本身没有被提供在啤酒数据集中列出的啤酒的风格,它只在用户提供的文本评论上被训练。然而,个人有时会在评论中提及啤酒风格。有 112 种独特的风格,所以为了简单起见,我们将一些风格进行分类。例如,有一吨不同风格的 IPA,淡色啤酒,黑啤酒等。下面让任何风格的 IPA 都只是‘IPA’。俄罗斯帝国黑啤、美国黑啤、出口黑啤等都将是:黑啤。下面的代码可以做到这一点。这是一种粗线条的绘画,但它有助于视觉化
# Reduces number of unique beer styles from 112 to 64beers['style'] = beers['style'].apply(lambda x: 'IPA' if 'IPA' in x else x)
beers['style'] = beers['style'].apply(lambda x: 'Stout' if 'Stout' in x else x)
beers['style'] = beers['style'].apply(lambda x: 'Lager' if 'Lager' in x else x)
beers['style'] = beers['style'].apply(lambda x: 'Porter' if 'Porter' in x else x)
beers['style'] = beers['style'].apply(lambda x: 'Lager' if 'Lager' in x else x)
beers['style'] = beers['style'].apply(lambda x: 'German' if 'German' in x else x)
beers['style'] = beers['style'].apply(lambda x: 'Pale' if 'Pale' in x else x)
beers['style'] = beers['style'].apply(lambda x: 'Barleywine' if 'Barleywine' in x else x)# This is for matching Doc2Vec Doc Tags to the beer dataframe
beers['id'] = beers['id'].astype(str)
现在让我们绘制啤酒风格的子集,看看分离!
# iterates through every unique beer style and plots with color
fig = plt.figure()
ax = plt.subplot(111)
for style in beers['style'].unique():
style_subset = make_tsne_subset(df, beers, style)
plt.scatter(style_subset['x'],style_subset['y'], s=0.4, alpha=0.4)

这本身并不是很好的视觉化,因为有 64 种风格,没有足够的颜色来涵盖每一种!例如,不同组中的红色都是不同的组。
中间和顶部的紫色/蓝色集群是所有的“淡色”和“IPA”啤酒。
但是让我们仔细看看其他一些风格!
dark_styles = ['Stout', 'Porter', 'Barleywine', 'Belgian Quadrupel (Quad)', 'Belgian Strong Dark Ale', 'Pumpkin Beer','Scotch Ale / Wee Heavy']fig = plt.figure(figsize=(9,5))
ax = plt.subplot(111)for style in dark_styles:
style_subset = make_tsne_subset(df, beers, style)
plt.scatter(style_subset['x'],style_subset['y'], s=1.5, alpha=0.4)ax.legend(dark_styles,\
bbox_to_anchor =(1,1), markerscale=10)plt.title('t-SNE plot of dark/heavy beers')
plt.tight_layout()

看那个!一些有趣的事情:
-比利时四倍啤酒和比利时浓黑啤酒密切相关,并形成他们自己独立的集群
-我们可以看到大麦酒的两个不同的集群-记得我们将英国和美国的大麦酒合并为一个类别!
——南瓜啤酒都是自带的(苏格兰麦芽酒也一样)!这一组中的黑啤酒和搬运工,无疑是南瓜品种,但我的重新标记使他们被放入更广泛的类别
-黑啤酒/搬运工,风格上有很多重叠,但在各种子风格中仍然有一些明显的聚类
现在让我们看看酸味“谱”上的东西:
sour_styles = ['Berliner Weisse', 'Belgian Saison', 'Leipzig Gose', 'Belgian Fruit Lambic', 'Belgian Lambic', 'Flanders Oud Bruin', 'Flanders Red Ale','American Wild Ale', 'Belgian Gueuze']fig = plt.figure(figsize=(7,5))
ax = plt.subplot(111)
for style in sour_styles:
style_subset = make_tsne_subset(df, beers, style)
plt.scatter(style_subset['x'],style_subset['y'], s=1.5, alpha=0.4)ax.legend(sour_styles,\
loc=5,bbox_to_anchor =(1.4,0.3), markerscale=10)plt.title('t-SNE plot of sour-ish beers')
plt.tight_layout()

有点混乱,但在谈到酸味时也有很多风格重叠。比利时的 Gueuze、Lambic 和 Flanders 啤酒是受保护的风格。许多美国啤酒厂会用传统的方式酿造,但是他们不能给他们的啤酒贴上这样的标签。我想这可以解释右边的重叠部分
——我想两组柏林维斯描述的是更酸(在美国野生麦芽酒里)和不那么酸(在 Gose 集群附近)
总的来说,我对这个模型以及它是如何从杂乱多变的评论数据中学习的非常满意。如果你想看看互动和部署版本,请访问这里:【https://tinyurl.com/beer30rec
创建更吸引人的 Word 云演示文稿
为了更好地吸引听众的注意力并传达你的观点

作者创造的形象
作为一名数据科学家甚至是数据爱好者,有时您会从事文本分析项目。在这个分析过程中,我们一直做的一件事是以词云的形式呈现最频繁出现的词。
如果你不知道什么是单词云,你可以看看上面的图片。就是一个词云的例子。单词出现的频率越高,它们在单词云中的大小就越大。这个词云有助于展示你的洞察力,以吸引任何不知情的观众。
问题是,大多数单词云演示都是乏味的,无聊的——它只是一堆单词,没有能力抓住观众的心。就看下面的云这个词。

作者创造的形象
当你看到上面的单词 cloud 时,你意识到它是来自格林兄弟灰姑娘故事的单词 cloud。你之所以意识到这一点,是因为频繁出现的单词显示的是灰姑娘的单词。
好吧,为了吸引人的展示,我们可以用其他形式来展示。例如以拖鞋的形式。

作者创造的形象
那么,我们如何将我们的单词云重塑成更好的形式呢?
stylecloud
我们可以通过使用名为 stylecloud 的 python 包来创建一个很酷的单词云。
这个软件包让我们用几行代码创建一个快速、时尚的单词云。让我们从安装包开始。对于还没有基础 word cloud 包的人,我们也可以下载。
pip install wordcloud
pip install stylecloud
当你安装好这些包后,我们就可以创建我们的单词云了。要定义你想要的单词云的形状,你需要从 fontawesome 网站找到你想要的图标。
在这里,您需要选择图标并找到图标上方的类参数。它应该显示类似这样的内容。

在那之后,你需要准备你想要的文本来显示在你的单词云中。在我的情况下,我会尝试呈现格林的红色小红帽单词云。
现在,让我们尝试运行该命令。
import stylecloud#We would use gen_stylecloud to shape our word cloud. I put my text #into a variable called "red".
#For parameter, icon_name is the class name from the font awesome that you choose and output_name is the name of the filestylecloud.gen_stylecloud(red, icon_name= "fab fa-wolf-pack-battalion", output_name = 'red.png')
如果你用和我一样的图标,它会像这样显示云这个词。

作者创建的图像
输出是本地文件夹中的图像文件。您可以在 jupyter 笔记本或您使用的任何 IDE 的同一文件夹中找到它。
那么,如果你想创建一个词云,但你自己的形状呢?在这种情况下,我们需要稍微解决一下。
字云与我们自己的形状
当我们为单词云创建形状时,我们实际上创建了一个遮罩作为放置单词的指导。
要遮罩单词云,我们需要首先从我们想要的图像中创建遮罩。我之前的情况是灰姑娘的鞋跟,就是这个样子。

作者创造的形象
为了确保单词云具有您想要的适当形状,您需要将形状设置为全彩色(除白色之外的任何颜色),并且在您不希望放置单词的任何地方将背景设置为全白色(#FF 或#FFFFFF)。
图像准备好了,现在我们可以试着先创建蒙版。掩码首先需要转换成一个数字数组。我们将使用 PIL 软件包中的数字和图像来实现这一点。
import numpy as np
from PIL import Image#My file name is called 'cinderella-heel.png'
mask = np.array(Image.open('cinderella-heel.png'))
当我们有了遮罩,我们现在就可以创建成形的单词云了。你可以按照我的命令行来创建单词云。我将使用我之前提到的灰姑娘故事,并将其输入到名为“cinder”的变量中。
from wordcloud import WordCloud, STOPWORDS
import matplotlib.pyplot as plt#Here we specify the width, height, background color, stopwords to use and the mask. The wordsword_cloud = WordCloud(width = 500, height = 500, background_color='white', stopwords=STOPWORDS, mask=mask).generate(cinder)plt.figure(figsize=(10,8))
plt.imshow(word_cloud)
plt.axis('off')
plt.tight_layout(pad=0)
plt.show()

作者创造的形象
就是这样。现在,您可以创建一个吸引人的可展示的单词云来展示您的演示文稿。
结论
词云通常用于文本分析,以找到令人兴奋的见解。问题是,它太乏味了。
出于这个原因,我们可以将单词 cloud 塑造成更好的形式,以获得更好的美感。
我们可以使用样式云来创建一个快速漂亮的单词云,或者使用遮罩技术来创建你自己的形状。
希望有帮助!
如果你喜欢我的内容,并想获得更多关于数据或作为数据科学家的日常生活的深入知识,请考虑在这里订阅我的时事通讯。
如果您没有订阅为中等会员,请考虑通过我的推荐订阅。
使用深度学习创建国际象棋人工智能
使用神经网络解码世界上最古老的游戏…

哈桑·帕夏在 Unsplash 上的照片
当加里·卡斯帕罗夫被 IBM 的深蓝国际象棋算法废黜时,该算法没有使用机器学习,或者至少以我们今天定义机器学习的方式使用。
本文旨在通过使用神经网络,一种更新形式的机器学习算法,使用神经网络来创建一个成功的国际象棋人工智能。
概念:
使用超过 20,000 个实例的国际象棋数据集(联系 victorwtsim@gmail.com 获取数据集),当给定一个棋盘时,神经网络应该输出一个移动。
下面是代码的 github 回购:
代码:
第一步|准备:
import os
import chess
import numpy as np
import pandas as pd
from tensorflow import keras
from tensorflow.keras import layers
这些库是创建程序的先决条件:操作系统和 pandas 将访问数据集,python-chess 是测试神经网络的“即时”棋盘。Numpy 是执行矩阵操作所必需的。Keras 的任务是创建神经网络。
第 2 步|访问数据:
os.chdir('XXXXXXXXXXX')
df = pd.read_csv('chess_normalized.csv')
data = df['moves'].tolist()[:500]
split_data = []
indice = 500
对于这个项目,我们需要的只是数据集中每个棋局的 pgn。请更改 os.chdir 函数的目录路径,以访问数据集所在的目录。
第三步|热门词典:
chess_dict = {
'p' : [1,0,0,0,0,0,0,0,0,0,0,0],
'P' : [0,0,0,0,0,0,1,0,0,0,0,0],
'n' : [0,1,0,0,0,0,0,0,0,0,0,0],
'N' : [0,0,0,0,0,0,0,1,0,0,0,0],
'b' : [0,0,1,0,0,0,0,0,0,0,0,0],
'B' : [0,0,0,0,0,0,0,0,1,0,0,0],
'r' : [0,0,0,1,0,0,0,0,0,0,0,0],
'R' : [0,0,0,0,0,0,0,0,0,1,0,0],
'q' : [0,0,0,0,1,0,0,0,0,0,0,0],
'Q' : [0,0,0,0,0,0,0,0,0,0,1,0],
'k' : [0,0,0,0,0,1,0,0,0,0,0,0],
'K' : [0,0,0,0,0,0,0,0,0,0,0,1],
'.' : [0,0,0,0,0,0,0,0,0,0,0,0],
}alpha_dict = {
'a' : [0,0,0,0,0,0,0],
'b' : [1,0,0,0,0,0,0],
'c' : [0,1,0,0,0,0,0],
'd' : [0,0,1,0,0,0,0],
'e' : [0,0,0,1,0,0,0],
'f' : [0,0,0,0,1,0,0],
'g' : [0,0,0,0,0,1,0],
'h' : [0,0,0,0,0,0,1],
}number_dict = {
1 : [0,0,0,0,0,0,0],
2 : [1,0,0,0,0,0,0],
3 : [0,1,0,0,0,0,0],
4 : [0,0,1,0,0,0,0],
5 : [0,0,0,1,0,0,0],
6 : [0,0,0,0,1,0,0],
7 : [0,0,0,0,0,1,0],
8 : [0,0,0,0,0,0,1],
}
一键编码是必要的,以确保没有特征或某些实例的权重高于其他特征或实例,从而在数据中产生偏差并阻碍网络的学习。pgn 值中的每个移动和配置都被改变成矩阵,在适当的列中具有 1。
步骤 4|准备数据的初步功能:
def make_matrix(board):
pgn = board.epd()
foo = []
pieces = pgn.split(" ", 1)[0]
rows = pieces.split("/")
for row in rows:
foo2 = []
for thing in row:
if thing.isdigit():
for i in range(0, int(thing)):
foo2.append('.')
else:
foo2.append(thing)
foo.append(foo2)
return foodef translate(matrix,chess_dict):
rows = []
for row in matrix:
terms = []
for term in row:
terms.append(chess_dict[term])
rows.append(terms)
return rows
这两个函数是将板翻译成 ascii 形式然后翻译成矩阵的两个初步函数。
第 5 步|创建数据:
for point in data[:indice]:
point = point.split()
split_data.append(point)
data = []
for game in split_data:
board = chess.Board()
for move in game:
board_ready = board.copy()
data.append(board.copy())
board.push_san(move)
trans_data = []
for board in data:
matrix = make_matrix(board)
trans = translate(matrix,chess_dict)
trans_data.append(trans)
pieces = []
alphas = []
numbers = []
对于神经网络的输入,板本身就足够了:板本身保存时态数据,尽管顺序不正确。添加多个板来形成临时数据对我可怜的 8GB 内存来说计算量太大了。
将原始输入作为移动将移除时态数据,并阻止卷积层从数据中提取特征。在第一行中,变量 indice 是可选的。我添加了这个变量来减少数据大小,以便在向上扩展之前测试网络和数据是否正常工作。
第 6 步|转换数据:
true_data = flatten(split_data)
for i in range(len(true_data)):
try:
term = flatten(split_data)[i]
original = term[:]
term = term.replace('x','')
term = term.replace('#','')
term = term.replace('+','')
if len(term) == 2:
piece = 'p'
else:
piece = term[0]
alpha = term[-2]
number = term[-1]
pieces.append(chess_dict[piece])
alphas.append(alpha_dict[alpha])
numbers.append(number_dict[int(number)])
except:
pass
这段代码通过使用 try except 函数并删除 check 或 checkmate 的所有额外符号,删除了所有不能一键编码的实例。
不幸的是,这意味着程序永远也学不会城堡。
步骤 7|创建神经网络:
board_inputs = keras.Input(shape=(8, 8, 12))conv1= layers.Conv2D(10, 3, activation='relu')
conv2 = layers.Conv2D(10, 3, activation='relu')
pooling1 = layers.MaxPooling2D(pool_size=(2, 2), strides=None, padding="valid", data_format=None,)
pooling2 = layers.MaxPooling2D(pool_size=(2, 2), strides=None, padding="valid", data_format=None,)
flatten = keras.layers.Flatten(data_format=None)x = conv1(board_inputs)
x = pooling1(x)
x = conv2(x)
x = flatten(x)
piece_output = layers.Dense(12,name = 'piece')(x)model_pieces = keras.Model(inputs=board_inputs, outputs=piece_output, name="chess_ai_v3")
earlystop = keras.callbacks.EarlyStopping(monitor='loss', min_delta=0, patience=250, verbose=0, mode='auto', baseline=None, restore_best_weights=True)
model_pieces.compile(
loss=keras.losses.mse,
optimizer=keras.optimizers.Adam(),
metrics=None,
)
model_pieces.fit(trans_data[:len(pieces)],pieces[:len(pieces)],batch_size=64, epochs=100,callbacks = [earlystop])
clear_output()board_inputs = keras.Input(shape=(8, 8, 12))conv1= layers.Conv2D(10, 3, activation='relu')
conv2 = layers.Conv2D(10, 3, activation='relu')
pooling1 = layers.MaxPooling2D(pool_size=(2, 2), strides=None, padding="valid", data_format=None,)
pooling2 = layers.MaxPooling2D(pool_size=(2, 2), strides=None, padding="valid", data_format=None,)
flatten = keras.layers.Flatten(data_format=None)x = conv1(board_inputs)
x = pooling1(x)
x = conv2(x)
x = flatten(x)
alpha_output = layers.Dense(7,name = 'alpha')(x)model_alpha = keras.Model(inputs=board_inputs, outputs=alpha_output, name="chess_ai_v3")
earlystop = keras.callbacks.EarlyStopping(monitor='loss', min_delta=0, patience=250, verbose=0, mode='auto', baseline=None, restore_best_weights=True)
model_alpha.compile(
loss=keras.losses.mse,
optimizer=keras.optimizers.Adam(),
metrics=None,
)
model_alpha.fit(trans_data[:len(alphas)],alphas[:len(alphas)],batch_size=64, epochs=100,callbacks = [earlystop])
clear_output()board_inputs = keras.Input(shape=(8, 8, 12))conv1= layers.Conv2D(10, 3, activation='relu')
conv2 = layers.Conv2D(10, 3, activation='relu')
pooling1 = layers.MaxPooling2D(pool_size=(2, 2), strides=None, padding="valid", data_format=None,)
pooling2 = layers.MaxPooling2D(pool_size=(2, 2), strides=None, padding="valid", data_format=None,)
flatten = keras.layers.Flatten(data_format=None)x = conv1(board_inputs)
x = pooling1(x)
x = conv2(x)
x = flatten(x)
numbers_output = layers.Dense(7,name = 'number')(x)model_number = keras.Model(inputs=board_inputs, outputs=numbers_output, name="chess_ai_v3")
earlystop = keras.callbacks.EarlyStopping(monitor='loss', min_delta=0, patience=250, verbose=0, mode='auto', baseline=None, restore_best_weights=True)
model_number.compile(
loss=keras.losses.mse,
optimizer=keras.optimizers.Adam(),
metrics=None,
)model_number.fit(trans_data[:len(numbers)],numbers[:len(numbers)],batch_size=64, epochs=100,callbacks = [earlystop])
clear_output()
该神经网络是一个卷积神经网络,具有从数据中提取特征的最大池。这种神经网络结构对于要预测的三个变量中的每一个都是重叠的:棋子、alpha(列)和 number(行)。
有一些我在设计神经网络时无法避免的致命缺点:
- 神经网络可能会预测不合法的举动
- 神经网络的拓扑为预测每个特征创建了一个断开点
如果你认为你能解决它,请随意使用这段代码来改进我的程序!
第八步|做预测:
new_chess_dict = {}
new_alpha_dict = {}
new_number_dict = {}
for term in chess_dict:
definition = tuple(chess_dict[term])
new_chess_dict[definition] = term
new_chess_dict[term] = definition
for term in alpha_dict:
definition = tuple(alpha_dict[term])
new_alpha_dict[definition] = term
new_alpha_dict[term] = definition
for term in number_dict:
definition = tuple(number_dict[term])
new_number_dict[definition] = term
new_number_dict[term] = definitiondata = np.reshape(trans_data[0],(1,8,8,12))
pred = model_pieces.predict(data)
def translate_pred(pred):
translation = np.zeros(pred.shape)
index = pred[0].tolist().index(max(pred[0]))
translation[0][index] = 1
return translation[0]
piece = translate_pred(model_pieces.predict(data))
alpha = translate_pred(model_alpha.predict(data))
number = translate_pred(model_alpha.predict(data))
piece_pred = new_chess_dict[tuple(piece)]
alpha_pred = new_alpha_dict[tuple(alpha)]
number_pred = new_number_dict[tuple(number)]
move =str(piece_pred)+str(alpha_pred)+str(number_pred)
为了解码来自各个神经网络的预测,必须创建反向字典:这意味着采用一次性编码并将其翻译成字符串。这在通过颠倒术语和定义而创建的 new_chess_dict、new_alpha_dict 和 new_number_dict 字典中有详细描述。
有了这最后一点代码,程序就完成了!
结论:
虽然神经网络在进行预测方面起作用,但它经常预测非法移动,因为移动范围对于非法移动范围是连续的。我不能为此创造一个新的解决方案,但我想到了一个新的方法来实现一个具有不同算法的象棋人工智能:遗传算法!敬请关注!
我的链接:
如果你想看更多我的内容,点击这个 链接 。
使用深度学习来训练深度搜索象棋算法
以及理解神经网络如何被用来间接解决问题

哈桑·帕夏在 Unsplash 上的照片
在大多数国际象棋引擎中,搜索算法和启发式函数为国际象棋人工智能提供了对最佳走法的主要洞察力。大部分的编程和这背后的大部分“大脑”是启发式函数。
我说的启发式函数是什么意思?启发式函数是指对棋盘进行一定的度量,对每个度量赋予一定的权重,最后计算出每个棋手优势的一个数值的函数。国际象棋中的启发式函数通常考虑基本的东西,如棋子结构、中心控制和国王安全,但它也可以包括更复杂的计算,如节奏和采用不同战术的机会。
一个经验丰富、编程熟练的棋手能够构造一个好的启发式函数。不幸的是,我不是那种经验丰富的棋手。我已经决定使用神经网络为我创建一个启发式函数。
概念:
该程序的概念是使用神经网络来评估电路板,然后安装搜索算法,检查所有未来位置并找到最高值,有点像最小-最大树。
程序:
步骤 1-访问数据:
from pandas import read_csv
import numpy as np
import chess
import osdf = read_csv('C:\\Users\\v_sim\\Desktop\\Files\\Data\\chess.csv')
df = df[df['winner']!='draw']
moves = df['moves'].values[:100]
winner = df['winner'].values
X = []
y = []
该脚本从我的电脑中提取 csv 文件,并导入程序运行所需的导入内容。Pandas 用于 csv 数据提取,numpy 用于数组操作,chess 用于现成的棋盘,空列表用于表示网络的 X 和 y 值。
步骤 2-数据先决条件:
def make_matrix(board):
pgn = board.epd()
foo = []
pieces = pgn.split(" ", 1)[0]
rows = pieces.split("/")
for row in rows:
foo2 = []
for thing in row:
if thing.isdigit():
for i in range(0, int(thing)):
foo2.append('.')
else:
foo2.append(thing)
foo.append(foo2)
return foodef translate(matrix,chess_dict):
rows = []
for row in matrix:
terms = []
for term in row:
terms.append(chess_dict[term])
rows.append(terms)
return rowschess_dict = {
'p' : [1,0,0,0,0,0,0,0,0,0,0,0],
'P' : [0,0,0,0,0,0,1,0,0,0,0,0],
'n' : [0,1,0,0,0,0,0,0,0,0,0,0],
'N' : [0,0,0,0,0,0,0,1,0,0,0,0],
'b' : [0,0,1,0,0,0,0,0,0,0,0,0],
'B' : [0,0,0,0,0,0,0,0,1,0,0,0],
'r' : [0,0,0,1,0,0,0,0,0,0,0,0],
'R' : [0,0,0,0,0,0,0,0,0,1,0,0],
'q' : [0,0,0,0,1,0,0,0,0,0,0,0],
'Q' : [0,0,0,0,0,0,0,0,0,0,1,0],
'k' : [0,0,0,0,0,1,0,0,0,0,0,0],
'K' : [0,0,0,0,0,0,0,0,0,0,0,1],
'.' : [0,0,0,0,0,0,0,0,0,0,0,0],
}
这个脚本能够将类板转换成一个一键编码的棋盘。这是通过首先访问板的 epd 形式,然后将其分成行,最后使用字典翻译所有的方块来完成的。
步骤 3-创建数据集:
for game in moves:
index = list(moves).index(game)
all_moves = game.split()
total_moves = len(all_moves)
if winner[index] == 'black':
game_winner = -1
else:
game_winner = 1
board = chess.Board()
for i in range(len(all_moves)):
board.push_san(all_moves[i])
value = game_winner * (i/total_moves)
matrix = make_matrix(board.copy())
rows = translate(matrix,chess_dict)
X.append([rows])
y.append(value)
X = np.array(X).reshape(len(X),8,8,12)
y = np.array(y)
X.shape
信不信由你,这是所有奇迹发生的地方。神经网络将直接跳到将死,而不是使用棋子结构和发展来计算玩家的优势。
我加载的数据集包括超过 14000 盘棋,给出了开局和走法的详细信息。我将为网络合成的数据将通过学习值“在玩家 X 将死之前还有多少步”来尝试和计算启发值。它通过数以千计的游戏来学习这种模式,直到它牢牢掌握了玩家的优势。
步骤 4-初始化神经网络:
from keras import callbacks, optimizers
from keras.layers import (LSTM, BatchNormalization, Dense, Dropout, Flatten,
TimeDistributed)
from keras.layers.convolutional import Conv2D, MaxPooling2D
from keras.models import Sequential, load_model, model_from_json
model = Sequential()
model.add(Conv2D(filters=64, kernel_size=1, activation='relu', input_shape=(8,8,12)))
model.add(MaxPooling2D())
model.add(Conv2D(filters=24, kernel_size=1, activation='relu'))
model.add(MaxPooling2D())
model.add(Conv2D(filters=10, kernel_size=1, activation='relu'))
model.add(Flatten())
model.add(BatchNormalization())
model.add(Dense(1,activation = 'tanh'))model.predict(X)
这是一个基本的卷积神经网络,除了在前向传播回路的末端使用双曲正切。在这种情况下使用双曲正切,因为每个棋盘的属性值可以在-1 和 1 之间,这完全符合双曲正切的范围。
步骤 5-训练网络:
from matplotlib import pyplot as plt
model.compile(optimizer='Nadam', loss='mse')
dirx = 'C:\\Users\\v_sim\\Desktop\\Files\\Programs\\ML\\Best Models'
os.chdir(dirx)
h5 = 'chess' + '_best_model' + '.h5'
checkpoint = callbacks.ModelCheckpoint(h5,
monitor='loss',
verbose=0,
save_best_only=True,
save_weights_only=True,
mode='auto',
period=1)
es = callbacks.EarlyStopping(monitor='loss', mode='min', verbose=1, patience=5000/10)
callback = [checkpoint,es]
json = 'chess' + '_best_model' + '.json'
model_json = model.to_json()
with open(json, "w") as json_file:
json_file.write(model_json)
print('Training Network...')
history = model.fit(X,y,epochs = 1000,verbose = 2,callbacks = callback)
plt.plot(history.history['loss'])
这是使用顺序 keras 模型进行机器学习的简单训练设置。
步骤 6-观察评估:
randint = np.random.randint(1,len(moves))
randint2 = np.random.randint(1,len(moves[randint].split()))
board = chess.Board()
for i in range(randint2):
board.push_san(moves[randint].split()[i])
matrix = make_matrix(board.copy())
rows = translate(matrix,chess_dict)
print('Board Evaluation:',model.predict([rows])[0][0])
board
这一步是可选的,只是为了看看你的网络评估是否合理。当使用上述训练参数训练神经网络时,以下是一些结果:

这个评价是对的。白棋处于很大的劣势,将他的白皇后移动到 c6 上的骑士可以拿的方格内。这就给了黑棋很大的物质优势。
请记住,范围在-1 和 1 之间,-1 代表将死黑色,1 代表将死白色
这个确切值的原因还不清楚,但是神经网络是一个黑盒:它没有明确定义的规则来计算这个值

这一评估表明,机器人理解发展的概念,以及发展如何导致将死。白棋对中锋有绝对的控制,有车沿着 e 档支援。
骑士在中心有一个强大的前哨,盯着 f7 上的兵。在正确的支持下,对 f7 卒的攻击可以导致对皇后和石头的分叉。此外,没有兵可以攻击黑夜,除非 f6 上的骑士离开。
步骤 7-深度搜索算法:
import chess
flatten = lambda l: [item for sublist in l for item in sublist]
def search_positions(board,depth):
#legal_moves = str(boards[depth][board].legal_moves)[38:-2].replace(',','').split()
depth_list = []
for i in range(depth+1):
depth_list.append([])
depth_list[0].append(board)
for layer in depth_list:
layer_set = []
try:
stet = flatten(layer)
except:
stet = layer
for i in range(len(stet)):
legal_moves = str(stet[i].legal_moves)[38:-2].replace(',','').split()
legal_moveset = []
for move in legal_moves:
neo_board = stet[i].copy()
neo_board.push_san(move)
legal_moveset.append(neo_board)
layer_set.append(legal_moveset)
if depth_list.index(layer)+1 == len(depth_list):
break
depth_list[depth_list.index(layer)+1] = layer_set
return depth_list
boards = search_positions(chess.Board(),2)
我不会深入研究我的深度搜索算法是如何工作的,它只是使用 python-chess 库中的合法走法和基本的列表函数来创建一个可能走法的树。
因为我只使用深度 2,所以我只需要评估最后一组移动。当考虑每一步棋的最坏情况时,检查哪一步棋有最好的最坏情况,也就是在这种情况下最好的棋。
为了在不使用其他复杂的迭代器工具的情况下评估棋盘,我想到了一个有趣的“try:,except:”结构的应用程序,它将自己索引到下一个列表中,直到找到一个棋盘:
def evaluate(lst):
for i in range(len(lst)):
try:
matrix = make_matrix(lst[i])
rows = translate(matrix,chess_dict)
lst[i] = model.predict([rows])
except:
evaluate(lst[i])
return lstevaluation = evaluate(boards[-1])
酷吧?
maximum = 0
for term in evaluation:
if np.mean(term) > maximum:
maximum = np.mean(term)
index = evaluation.index(term)
这个最后的脚本向你展示了在给定的情况下最好的行动。
结论:
我认为这个程序是一个有趣的案例,其中神经网络不是最终的解决因素,而是机器学习问题最终解决方案的垫脚石。我认为,人们低估了神经网络绕过复杂的中间障碍的能力,这些障碍阻止人们达到目标。
希望更多的人在更复杂的项目中使用神经网络作为中间步骤。
我的链接:
如果你想看更多我的内容,点击这个 链接 。
使用 Scikit-Learn 创建基于类的 TF-IDF

作者与https://www.woordwolk.nl/一起创作
自然语言处理
提取每个类别的信息词
在我之前的一篇帖子中,我谈到了与 BERT 的主题建模,其中涉及到一个基于类的版本 TF-IDF 。这个版本的 TF-IDF 允许我从一组文档中提取有趣的主题。
我认为深入一点这个方法可能会很有趣,因为它可以用于更多的应用,而不仅仅是主题建模!
可能的应用概述:
- 每个班级的信息词汇:哪些词汇让一个班级与众不同?
- 类别减少:使用 c-TF-IDF 减少类别数量
- 半监督建模:仅使用余弦相似度和 c-TF-IDF 来预测未见过的文档的类别
本文将主要讨论**c-TF-IDF**的应用,但也会给出一些模型的背景。
如果你想跳过所有这些,直接进入代码你可以从回购 这里 开始。
基于类的 TF-IDF
在探讨这种基于类的 TF-IDF 的可能性之前,让我们先看看 TF-IDF 是如何工作的,以及我们需要采取哪些步骤来将其转换为 c-TF-IDF。
TF-IDF
TF-IDF 是一种从文本文档生成特征的方法,它是两种方法相乘的结果:
- 词频( TF )
- 逆文档频率( IDF )
词频仅仅是文档中的原始字数,其中每个字数被认为是一个特征。
逆文档频率通过计算一个单词在一个文档中的频率与它在所有其他文档中的频率相比,来提取某些单词的信息量。

逆文档频率。此处检索到。
你可以想象诸如the、and、I等词语。是非常常见的单词,但包含的信息非常少,因为它们几乎出现在每个文档中。逆文档频率惩罚过于常见的单词。
结果是一个稀疏的特征矩阵,可用于特征提取、预测建模和文档相似性。
将 TF-IDF 转化为 c-TF-IDF
基于类的 TF-IDF 的目标是为单个类中的所有文档提供相同的类向量。为了做到这一点,我们必须开始从基于类的角度而不是单个文档的角度来看待 TF-IDF。
如果文档不是个体,而是一个更大的集体的一部分,那么通过将所有文档加入到一个类中,实际上把它们看作个体可能会很有趣。
结果将是一个非常长的文档,它本身实际上是不可读的。想象一下阅读一份由 10 000 页组成的文档!
然而,这允许我们开始从基于类的角度来看待 TF-IDF。
然后,不是将 TF-IDF 应用于新创建的长文档,我们必须考虑到,自从我们合并文档以来,TF-IDF 将采用类的数量而不是文档的数量。
对 TF-IDF 的所有这些更改导致以下公式:

图片由作者提供。
其中为每个类别**i**提取每个单词**t**的频率并除以单词总数**w**。这个动作可以看作是对课堂上常用词的一种正则化形式。接下来,未连接的文档总数**m**除以所有类别**n**中单词**t**的总频率。
密码
当我在 BERT 帖子的主题建模中介绍 c-TF-IDF 时,我使用了一种低效的方法来计算 c-TF-IDF。
从那以后,我创建了一个 c-TF-IDF 版本,它不仅允许大幅加速,而且还利用了 T21 Scikit-Learn 中的 TFidfTransformer,它允许我们使用 sci kit-Learn 提供的稳定性。
正如你所看到的,我们从TfidfTransformer开始,只采用拟合和变换的方法使其成为CtfidfVectorizer。矢量器接收包含原始计数数据的稀疏矩阵。
创建 c-TF-IDF 矩阵的最基本示例如下:
我们确保类中的所有文档在通过 CountVectorizer 之前被合并在一起,以计算最终通过 CTFIDFVectorizer 的原始计数数据。
注:通过CTFIDFVectorizer的n_samples是未接合单据的总数。这是必要的,因为如果通过的是合并的文档数,IDF 值会变得太小。
应用程序
如前所述,c-TF-IDF 大概有三种使用情况:
- 与其他所有的单词相比,哪些单词是某一特定类别的典型单词?
- 如何才能减少使用 c-TF-IDF 的班级数量?
- 如何在预测建模中使用 c-TF-IDF?
每类信息词
与 TF-IDF 相比,c-TF-IDF 的独特之处在于我们可以采用它来搜索组成特定类别的单词。
如果我们有一个被标记为 space 的类,那么我们会期望找到与空间相关的单词,对吗?
为此,我们只需提取 c-TF-IDF 矩阵,并找出每类中的最高值:

每类中价值最高的单词。图片由作者提供。
不出所料,这些单词很好地代表了它们所属的类别。您可以将此 c-TF-IDF 过程视为该课程内容的总结。
班级缩减
有时,拥有多个类可能不利于清晰的分析。您可能需要一个更全面的概述来了解数据中的主要类。
幸运的是,我们可以使用 c-TF-IDF 将类的数量减少到您想要的任何值。
我们可以通过将所有类别的 c-TF-IDF 向量相互比较来做到这一点,以便合并最相似的类别:

在合并之前提取最相似的类。图片由作者提供。
在 c-TF-IDF 向量上使用余弦相似性似乎有效!我们正确地发现,类atheism和christian可以合并成我们所谓的religion。我们发现autos和motorcycles的结果相似,它们可以组合在一起。
使用这种方法,我们可以选择最相似的类,只要它们足够相似,就可以进行组合。
半监督建模
使用 c-TF-IDF,我们甚至可以直接执行半监督建模,而不需要预测模型。
我们首先为训练数据创建一个 c-TF-IDF 矩阵。结果是每个类的一个向量,它应该代表那个类的内容。最后,我们检查以前未见过的数据,该向量与所有类别的向量有多相似:

虽然我们可以看到结果没有什么值得大书特书的,准确率大约为 50% …这个准确率比随机猜测的类别 5%要好得多。
在没有任何复杂的预测模型的情况下,我们设法用一个快速且相对简单的模型获得了相当不错的准确性。我们甚至没有对数据进行预处理!
感谢您的阅读!
如果你像我一样,对人工智能、数据科学或心理学充满热情,请随时在 LinkedIn 上添加我,或者在 Twitter 上关注我。
本文中的所有示例和代码都可以在这里找到:
c-TF-IDF 是一个基于类的 TF-IDF 过程,可用于根据文本文档生成特征…
github.com](https://github.com/MaartenGr/cTFIDF)



浙公网安备 33010602011771号