用 Julia 做数据分析
2020-08-28
周溱
据说,这是个大数据的时代。当然,我们普通人接触真正大数据的机会不多,但总要学一两招数据分析,否则也不好出来见人不是。假如你有一堆数据,通常在一个CSV文件里,你需要把数据处理一下,做一些图表,找一些规律,说明一些现象,你可能会用 excel 来做这件事,这没问题。
但假如这原始数据文件有几十上百个字段,几百万行呢?傻眼了吧。
这时候你需要真正强悍的家伙事儿。请看: Julia
什么是Julia
Julia是最近十年内出现的新型编程语言。通俗地说,它兼具 Matlab 的科学计算功能,和 R 的统计计算功能,语法更现代化,而且非常快. 这主要是因为:
- 它是基于LLVM的编译到底执行。
- 它是真正通用的编程环境,并不局限于计算
- 它有相当复杂的自动并行计算功能,充分利用你电脑的多个核心
假如你曾用过Matlab,Octave 或 R,但不是花过大量心血,还愿意尝试新鲜事物的话,不管你是专业从事数据分析处理,还是像我一样的业余爱好者,我建议你了解一下,跟我一起开始一段简短的旅程。
安装
当然,第一步是安装。请从官网下载安装。过程相当标准化,没什么好说的。然后,你就得到了一个命令行界面:
Dereks-MacBook-Pro:~ derek$ julia
_
_ _ _(_)_ | Documentation: https://docs.julialang.org
(_) | (_) (_) |
_ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 1.5.1 (2020-08-25)
_/ |\__'_|_|_|\__'_| | Official https://julialang.org/ release
|__/ |
julia>
你还可以尝试集成IDE Juno, 这是一个基于 Atom 的集成环境。我大致试用了一下,还不错,但对我个人意义不是特别大。当然我不是一个典型用户,大家不妨多尝试一下。
大型数据文件处理
现在回到我们开始的问题。我们有一个相当大的数据文件需要处理分析。Julia直接提供了相应的程序包,就是 DataFrames, 对应复杂类型的大型数据表格处理,和 CSV, 负责CSV文件的读取到 DataFrame 和从 DataFrame 输出到CSV文件。这些程序包都可以在julia命令行下安装:
julia> using Pkg
julia> Pkg.add("DataFrames")
julia> Pkg.add("CSV")
julia> using DataFrames, CSV
一大堆安装编译的输出之后,这两个包就安装好可以用了。
第一步是读入我们的数据文件:
df = CSV.read("/Users/derek/Downloads/Ridershare_data_triplevel_Sep2019_week1_nofilter.csv")
简单吧。这个文件有两百万行,但十秒钟之内就读入,生成成DataFrame了:
1978890×26 DataFrame. Omitted printing of 22 columns
│ Row │ Column1 │ Trip_ID │ Trip_Day │ Is_Weekend │
│ │ Int64 │ String │ String │ Bool │
├─────────┼─────────┼──────────────────────────────────────────┼──────────┼────────────┤
│ 1 │ 0 │ 0003eb321a18a94794a1f7953738569808fa38e5 │ Sunday │ 1 │
│ 2 │ 3874 │ ac3456ae1d86578e2ec442ff9d4f1d980af9b2cf │ Sunday │ 1 │
│ 3 │ 3873 │ ac30915385127ec33af27d30a92a8462d6c2c671 │ Sunday │ 1 │
│ 4 │ 3872 │ ac2ef27a1089d302638bbe39afb5c5462fea0235 │ Sunday │ 1 │
│ 5 │ 3871 │ ac1d012abf015bcb969e76710b3d1a29089a3a12 │ Sunday │ 1 │
第二步是删掉我们不用的列。同样很简单:
df = df[:, [:Trip_Start_Timestamp, :Trip_End_Timestamp, :Pickup_Census_Tract, :Dropoff_Census_Tract]]
1978890×4 DataFrame. Omitted printing of 1 columns
│ Row │ Trip_Start_Timestamp │ Trip_End_Timestamp │ Pickup_Census_Tract │
│ │ String │ String │ Int64? │
├─────────┼──────────────────────┼────────────────────────┼─────────────────────┤
│ 1 │ 2019-09-01 │ 09/01/2019 12:15:00 AM │ missing │
│ 2 │ 2019-09-01 │ 09/01/2019 12:15:00 AM │ 17031081402 │
│ 3 │ 2019-09-01 │ 09/01/2019 12:15:00 AM │ 17031071300 │
│ 4 │ 2019-09-01 │ 09/01/2019 12:15:00 AM │ 17031330100 │
│ 5 │ 2019-09-01 │ 09/01/2019 12:15:00 AM │ 17031842000 │
第三步是删掉数据不完整的行。原始文件通常都是有瑕疵的,需要一定的数据清洁。这在julia里非常简单:
julia> df = DataFrames.dropmissing(df)
1307900×4 DataFrame. Omitted printing of 1 columns
│ Row │ Trip_Start_Timestamp │ Trip_End_Timestamp │ Pickup_Census_Tract │
│ │ String │ String │ Int64 │
├─────────┼──────────────────────┼────────────────────────┼─────────────────────┤
│ 1 │ 2019-09-01 │ 09/01/2019 12:15:00 AM │ 17031081402 │
│ 2 │ 2019-09-01 │ 09/01/2019 12:15:00 AM │ 17031071300 │
│ 3 │ 2019-09-01 │ 09/01/2019 12:15:00 AM │ 17031330100 │
│ 4 │ 2019-09-01 │ 09/01/2019 12:15:00 AM │ 17031842000 │
│ 5 │ 2019-09-01 │ 09/01/2019 12:15:00 AM │ 17031839100 │
第四步是对列做一定数据处理。这其实需要写一点程序,但外围就是这样的:
julia> df = DataFrames.select(df,
:Trip_Start_Timestamp => ByRow(ts2integer) => :start,
:Trip_Start_Timestamp => ByRow(ts2integer) => :end,
:Pickup_Census_Tract => :pickup,
:Dropoff_Census_Tract => :dropoff)
1307900×4 DataFrame
│ Row │ start │ end │ pickup │ dropoff │
│ │ Int64 │ Int64 │ Int64 │ Int64 │
├─────────┼───────┼───────┼─────────────┼─────────────┤
│ 1 │ 0 │ 0 │ 17031081402 │ 17031320600 │
│ 2 │ 0 │ 0 │ 17031071300 │ 17031080300 │
│ 3 │ 0 │ 0 │ 17031330100 │ 17031841100 │
│ 4 │ 0 │ 0 │ 17031842000 │ 17031063200 │
│ 5 │ 0 │ 0 │ 17031839100 │ 17031833000 │
以上 ts2integer
函数是我自己根据数据格式和我的需要写的,这里就不贴了。
再往后,就是你自己的数据处理和统计分析,取决于你个人的想法。你需要最基础的画图工具包:
julia> Pkg.add("Plots")
julia> using Plots
我画的一个简单曲线如下:
批评
说了一堆优点,现在说缺点。
脉络不清晰
实话说,我看了这两天,Julia 语法的脉络我还没摸出来。Julia 既可以当 OOP 语言用,也可以当 FP 语言用,但二者都只能做到八成。这也是可以理解的,毕竟 OOP 和 FP 不能共存. 我感觉它太过求全求大,所以难以找到脉络。我个人学东西总希望先找到核心思想,再用核心思想去套细节,但在这里可能还要依赖于盲人摸象式学习。
文档无重点
Julia 在线文档不少,但可惜的是缺乏主次之分。好的文档能让新手上来不用全部看过就先能用上,解决一些简单问题。细节可以过后细细研究。但 Julia 的核心库文档还是以堆砌事实为主。更由于上一条本来脉络就不是很清晰,一些很简单的事情我在偌大文档里也难以找到答案,不得已借助谷歌搜索或 Stack Overflow 来寻求答案。在这点上,我前一段主力学习的 elixir 文档就好的多。
总结
Julia 已经不是新生事物。它已经有八年的历史,成熟的社区,和一个相当擅长的领域。从高阶来看, Matlab和 R 的 99% 的使用场景都可以被取代;从低阶应用来说,使用 Python 等通用脚本语言来做数值计算和统计分析也变得没有实际意义了。
Julia 是 100% 的自由软件。普通人,用普通家用电脑,已经可以做 GB 级别相当复杂的数据分析,只要你愿意花功夫。
颤抖吧,凡人。专业和业余的鸿沟正在消失。