2019 年 6 月

第 34 卷,第 6 期

[人工智能]

使用 R 浏览数据

作者 Frank La La | 2019 年 6 月 | 获取代码

Frank La Vigne从第一个人工智能列开始,已提供的所有代码示例都使用 Python。这是因为 Python 作为数据科学和 AI 的语言盛行一时。但它并非唯一,Scala 和 R 等语言在此领域占重要地位。对于想知道为何必须了解另一种编程语言的开发人员,R 有一些未曾在跨 Java、C#、Visual Basic、Python 和 Perl 的职业生涯中遇到的独特之处。将 R 作为读者可能会在数据科学领域中遇到的语言时,我认为值得对其进行探究。

R 本身是 S 编程语言的实现,该编程语言于 20 世纪 70 年代在贝尔实验室创建用于统计处理。S 旨在为当时与 Fortran 一起致力于统计处理的开发人员提供交互式体验。虽然我们现在认为交互式编程环境是理所当然的,但在当时具有革命意义。

R 由新西兰奥克兰大学的 Ross Ihaka 和 Robert Gentleman 于 1992 年提出,其名称从创建者的名字首字母派生而来,同时也适用于 S 的名称。R 的版本 1.0.0 已于 2000 年发布,部分得益于大量内置统计算法,已在研究部门中广为应用。它也可通过函数和扩展包轻松扩展。

可靠的开发人员社区已出现 R,将 R 包的最常用存储库作为 Comprehensive R Archive Network (CRAN)。CRAN 具有各种包,涵盖范围从 Bayesian 应计预测到高分辨率流注入质谱的光谱处理。可通过 bit.ly/2DGjuEJ 在线获得 CRAN 中的 R 包的完整列表。可以肯定地说,R 和 CRAN 为任何数据科学或科学研究项目提供功能强大的工具。

R 入门

运行 R 代码的最快方式可能是通过 Azure Notebook 服务上的 Jupyter Notebook。有关 Jupyter Notebook 的详细信息,请参阅有关此主题的 2018 年 2 月文章,网址为 msdn.com/magazine/mt829269。但是,这次请确保选择 R 作为创建新的笔记本时的语言。R 徽标应显示在浏览器窗口的右上角。在空白单元格中输入以下代码并执行它:

# My first R code
print("hello world")
x <- 3.14
y = 1.21
x
y

其输出应指明传统的“hello world”问候语,以及值 3.14 和 1.21。对于任何软件开发人员,这些都不应为新颖或唯一。请注意,赋值运算符也可以是“<-”,而不只是更常用的等号。这两个运算符在语法上相等。另请注意,# 字符引入了一条注释,并应用于该行的其余部分。

矢量是可以包含数值数据、字符数据或逻辑数据的一维数组。它们是使用 c 函数创建的。c 代表“合并”。 在新单元格中输入以下代码并执行它:

num_vec <- c(1,2,3.14) # numeric vector
char_vec <- c("blog","podcast","livestream") # character vector
bool_vec <- c(TRUE,TRUE,FALSE) #logical vector
#print out values
num_vec
char_vec
bool_vec

显示的值应与代码中设置的值匹配。你现在可能想知道向量是否可以包含混合类型。在新单元格中输入以下代码:

mix_vec <- c(1,"lorem ispum",FALSE)
mix_vec

运行该代码时,眼尖的读者会注意到矢量中每个元素周围的单引号。这表示值已转换为字符值。R 具有用来检查任何给定变量的类型的 typeof 函数。输入以下代码检查已创建的矢量:

typeof(num_vec)
typeof(char_vec)
typeof(bool_vec)
typeof(mix_vec)

需要了解的一个其他有用函数是 ls,它显示当前工作环境中的所有对象。在新单元格中输入“ls()”,执行它,并观察输出包含刚定义的四个矢量,以及第一个单元格中定义的 x 和 y 变量。

使用数据

体验 R 语言的实际强大功能和优雅的最佳方式是将其用于浏览和操作数据。使用 R,可以轻松加载数据集并快速了解其维度、结构和统计属性。在接下来的几个示例中,我将使用与我息息相关的数据集:有关我的博客活动的基本统计信息。我从 2004 年开始运行并维护技术博客,保留了有关每个月发布频率的基本统计信息。此外,我还添加了每个月中的天数和每日帖子数 (PPD) 的平均值。PPD 是给定月份中的帖子数除以该月的天数所得的值。我已将 CSV 文件放在 bit.ly/2V76d2G 中的 Azure Notebook 服务上的项目库中。

在新单元格中输入以下代码以将数据加载到 R 数据帧(包含变量列和观察结果行的表格数据结构),并分别使用 head 和 tail 函数显示前六个和后三个记录,如下所示:

postData <- read.csv(file="franksworldposts.csv", header=TRUE, sep=",")
head(postData)
tail(postData, 3)

使用 str 函数,我可以查看 DataFrame 的基本结构和数据类型。在新单元格中输入以下代码:

str(postData)

其输出应显示 DataFrame 具有 183 个观察结果或行,并且包含四个变量或列。Posts 和 Days.in.Month 变量是整数,而 PPD 是数值类型。Month 变量是包含 183 个级别的因子,其中因子是对应于统计信息中的分类变量的数据类型。因子在功能上相当于 Python Pandas 中的分类,可以是字符串或整数。它们适用于具有有限数量的唯一值或级别(在 R 术语中)的变量。在此 DataFrame 中,“月份”字段表示 2004 年 2 月和 2019 年 4 月之间的月份。由于日期不会重复,因此不会有重复的分类值。

现在已加载我的数据,我可以对其进行排序和查询,从而进一步探索。也许我可以从中得出一些见解。例如,如果我想要查看撰写博客最多的前 10 个月,我可以对“帖子”列执行降序排序。若要执行此操作,请在新单元格中输入以下代码并执行它:

sortedPostData <- postData[order(-postData$Posts),]
head(sortedPostData, 10)

最活跃的前 10 个月都在过去三年内。若要进一步探索数据集,我可以执行筛选操作来确定哪几个月份有 100 个或更多帖子。在 R 中,子集函数仅执行该操作。输入以下代码以应用此筛选器并将输出分配到称为 over100 的新 DataFrame,如下所示:

over100 <- subset(postData, subset = Posts >= 100)
over100

结果类似于前 10 个输出。若要检查行数,请使用 nrow 函数计算 DataFrame 中的行数,如下所示:

nrow(over100)

其输出表明有 11 行,其中包含给定月份内的 100 个或更多博客文章。2005 年 5 月发表了 100 个帖子,正好错过最活跃的前 10 个月,沦为第 11 名。清除每月 100 个帖子的阈值不是我 11 年以来再次达到的里程碑。是否有博客发表强度为先下降再上升的模式?让我们进一步检查数据。

现在是了解如何查看 DataFrame 中的各行各列的好时机。例如,若要查看 DataFrame 中的第一行,请输入以下代码以查看整行内容:

postData[1,]

请注意,DataFrame 的索引从 1(而不是 0)开始,大多数其他编程语言也是如此。若要仅查看第一行的“帖子”字段,请输入以下代码:

postData[1,2]

若要查看“帖子”字段中的所有值,请使用以下代码行:

postData[,2]

或者,也可以使用以下语法基于列名称显示列。输入以下代码行并确认其输出与之前的代码行中的输出匹配:

postData$Posts

由于 R 在统计处理中具有根,因此有许多可用来查看数据的基本形状和属性的内置函数。使用以下代码可更好地了解“帖子”列中的数据:

mean(postData$Posts)
max(postData$Posts)
min(postData$Posts)
summary(postData$Posts)

现在,将其与 PPD 列比较,如下所示:

mean(postData$PPD)
max(postData$PPD)
min(postData$PPD)
summary(postData$PPD)

我们从数据中看到帖子数量在过去 15 年期间从每个月 1 个转变为 225 个。如果我想要仅浏览第一年的数据,该怎么办?输入以下代码以仅显示第一年博客的记录,以及“帖子”和“PPD”字段的统计摘要:

postData[1:12,]
summary(postData[1:12,2]) # Posts
summary(postData[1:12,4]) # PPD

虽然此处的数字可以陈述事情,但通常是图表显示有关趋势和模式的详细信息。幸运的是,R 内置有丰富的绘图功能。我们来研究一下。

可视化数据

在 R 中创建绘图非常简单,只需一行代码即可完成。让我们先使用第一年的帖子计数和 PPD 值。下面是实现该目的的代码:

plot(postData[1:12,2], xlab="Month Index", ylab="Posts",
  main="Posts in the 1st Year")
plot(postData[1:12,4], xlab="Month Index", ylab="PPD",
  main="PPD in the 1st Year")

其输出应与图 1 类似。

绘制帖子和 PPD 列
图 1 绘制帖子和 PPD 列

在第一年的博客中,图表显示帖子活动稳步增多,其中第三个月和第六个月之间呈陡峭的增长曲线。在夏末下降之后,2004 年以极大增量结束。此外,图表显示每个月的帖子数与每天的帖子数之间具有较高的关联。虽然这可能很直观,但看到它显示在图表中还是非常有趣的。

现在,我想要查看整个 15 年范围内的博客文章的图表,看看是否会在较长一段时间内出现某种模式。输入以下代码绘制整个时间范围:

plot(postData[,2], xlab="Month Index", ylab="Posts",
  main="All Posts")

图 2 中显示的结果确实说明了一个明显趋势,甚至尚未明确定义的模式。博客活动一开始非常强劲,但稳步下降,在大约 30 个月之前再次上升。后期趋势为明显上升。此外,还有一个重要的离群值。

过去 15 年的帖子
图 2 过去 15 年的帖子

关联矩阵

早些时候,我已提到过帖子和 PPD 列之间的关联。R 拥有用于显示关联矩阵的内置函数,该矩阵是显示变量之间的关联系数的表。表中的每个单元格显示两个变量之间的关联。

关联矩阵快速汇总数据并显示变量之间的关系。接近 1 的值具有较高的关联,而接近 0 的值具有较低的关联。负值表示负关联。若要查看 postData DataFrame 的关联矩阵,必须先将数值字段隔离到其自己的 DataFrame 中,然后调用 cor 函数。将以下代码输入新单元格并执行它:

postsCor <- postData[, c(2, 3 ,4)]
cor(postsCor)

其输出显示帖子和 PPD 之间近乎完美的关联,而 Days.In.Month 与 PPD.之间略有负关联。

总结

虽然 R 的语法和方法可能不同于传统的编程语言,但我发现它是数据整理和数学处理的精妙解决方案。对于认真开创数据科学职业生涯的软件工程师,R 是待开发的一项重要技能。

在本文中,我探讨了 R 编程语言的一些基础知识。我介绍了如何使用内置函数来加载并浏览 DataFrames 中的数据,以便深入了解统计信息和绘制图表。实际上,本文中的所有内容都是以所谓的“基本”R 编写的,因为它不依赖于任何第三方包。但是,某些 R 用户更喜欢使用其他样式的包的“tidyverse”套件。我将在接下来的专栏中进行探讨。


Frank La Vigne 是 Microsoft 的 AI 技术解决方案专家,他通过充分利用分析后的数据和 AI 来帮助公司实现更大价值。他还共同主持 DataDriven 播客。他定期在 FranksWorld.com 上发表博客,你还可以在他的 YouTube 频道“Frank’s World TV”(FranksWorld.TV) 中看到他。

衷心感谢以下技术专家对本文的审阅:Andy Leonard、David Smith
David Smith 是 Microsoft 云大使,专注于人工智能和机器学习的主题。自 2009 年以来,他一直是 Revolutions 博客 (blog.revolutionanalytics.com) 的编辑,他在该网站中定期撰写有关数据科学应用的文章,并将重点放在 R 编程语言上。他也是 R Consortium 的创始成员。采用 @revodavid 的形式在 Twitter 上关注 David。


在 MSDN 杂志论坛讨论这篇文章