4 DataFrames.jl
此处的省略号表示这是一张非常长的表,但只显示了少数行。 在分析数据时,我们经常会提出一些关于数据的有趣问题,这也称为 数据查询。 对于大型表格,计算机能够比手工查询更快地回答此类问题。 一些 数据查询 问题的例子如下:
- 哪个电视节目评分最高?
- 哪些电视节目由美国制作?
- 哪些电视节目由相同的国家制作?
但是,作为研究人员,实际的科学往往从多张表格或多个数据源开始。 例如,如果我们也有其他人的电视节目评分数据 (表 2):
name | rating |
---|---|
Game of Thrones | 7 |
Friends | 6.4 |
… | … |
现在则能够提出以下问题:
- 节目 Game of Thrones 的平均评分是多少?
- 谁对 Friends 给出了最高的评分?
- 哪些节目你评分了,但其他人没有?
在本章的其余部分中,我们将展示如何借助 Julia 来轻松地回答这些问题。 因此此,首先说明为什么需要 Julia 包 。 下节将展示如何使用此包,最后将展示如何编写快速数据变换的代码 (Section )。
首先查看如下的成绩表 表 3 :
name | age | grade_2020 |
---|---|---|
Bob | 17 | 5.0 |
Sally | 18 | 1.0 |
Alice | 20 | 8.5 |
Hank | 19 | 4.0 |
其中 name 列的类型为 string
, age 列的类型为 integer
,而 grade 列的类型为 float
。
截至目前,本书只介绍了 Julia 的基础知识。 这些基础能够处理很多东西,但不能处理表。 因此,为了说明我们需要更多类型,让我们尝试将表格数据存储在数组中:
function second_row()
name, age, grade_2020 = grades_array()
i = 2
row = (name[i], age[i], grade_2020[i])
end
second_row()
或者,如果想获得 Alice 的成绩,首先需要弄清楚 Alice 所在的行:
function row_alice()
names = grades_array().name
i = findfirst(names .== "Alice")
end
row_alice()
3
然后才能得到成绩:
8.5
DataFrames.jl
可以很容易地处理此类问题。 首先使用 using
加载 DataFrames.jl
:
通过 DataFrames.jl
,我们可以定义 DataFrame
来存储表格数据:
names = ["Sally", "Bob", "Alice", "Hank"]
grades = [1, 5, 8.5, 4]
df = DataFrame(; name=names, grade_2020=grades)
即此处返回的变量 df
以表格格式存储数据。
function grades_2020()
grade_2020 = [1, 5, 8.5, 4]
DataFrame(; name, grade_2020)
end
grades_2020()
name | grade_2020 |
---|---|
Sally | 1.0 |
Bob | 5.0 |
Alice | 8.5 |
Hank | 4.0 |
注意, 和 grade_2020
会在函数返回后销毁,即它们仅在函数中可用。 这样做还有两个好处。 首先,读者可以清晰地看到 name
和 grade_2020
由谁所有:它们属于 2020 成绩表。 其次,很容易在书中的任何地方确定 grades_2020()
的输出。 例如,可以将数据赋给变量 df
:
name | grade_2020 |
---|---|
Sally | 1.0 |
Bob | 5.0 |
Alice | 8.5 |
Hank | 4.0 |
改变 df
的内容:
df = DataFrame(name = ["Malice"], grade_2020 = ["10"])
而且仍然能够无损恢复数据:
df = grades_2020()
name | grade_2020 |
---|---|
Sally | 1.0 |
Bob | 5.0 |
Alice | 8.5 |
Hank | 4.0 |
当然,此处假设没有重新定义函数。 我们在本书中保证不会这样做,因为这是非常糟糕的做法。 我们不会 “改变” 函数,而是创建一个具有明确名称的新函数。
因此,回到 DataFrames
构造器。 如你所见,创建方法是将向量作为参数传递给 DataFrame
构造器。 你可以给定任何合法的 Julia 向量,并且 只要向量长度相同,就能成功构造 DataFrame
。 重复的向量、Unicode 符号和任何类型的数字都可以:
DataFrame(σ = ["a", "a", "a"], δ = [π, π/2, π/3])
σ | δ |
---|---|
a | 3.141592653589793 |
a | 1.5707963267948966 |
a | 1.0471975511965976 |
通常,您在代码中会创建函数来包装一个或多个作用于 DataFrame
的函数。 例如,可以创建函数来获取一个或多个 names
的成绩:
function grades_2020(names::Vector{Int})
df = grades_2020()
df[names, :]
end
grades_2020([3, 4])
使用函数来包装基本功能的这种方式,在编程语言和包中非常常见。 基本上,你可以把 Julia 和 DataFrames.jl
看作基本模块的提供者。 它们提供了相当 通用的 模块,从而你可以在此基础之上实现一些 特例 ,比如这个成绩例子。 借助这些基本模块,你可以编写数据分析脚本,控制机器人或任何你想要构造的东西。
Jose Storopoli, Rik Huijzer, Lazaro Alonso, 刘贵欣 (中文翻译), 田俊 (中文审校)