首页
Preview

在Java中进行酷炫的数据科学:三个DataFrame库的比较

我一直在探索使用Java工具对大数据集进行简单数据分析的方法,因为我们在AppBrain.com的生产系统是基于Java的。

数据框架是R和Python(通过pandas)中的数据科学流行工具。一个好的数据框架实现使得导入数据、过滤和映射数据、计算新列、创建聚合等操作变得容易。

我从Github中选择了三个Java开源数据框架库:tablesawjoinerymorpheus(我也简要地看了一下datavec,但是无法实现我想要的,稍后会详细讲解)。作为一个玩具数据集,我从eurostat中提取了一些欧洲城市和国家的人口数据。

我使用这些库回答了两个简单的问题(关于数据集中的人口和相对增长)。在本文中,我将描述每个库的使用体验。

所有的代码都可以在GitHub仓库中找到。

数据

我从Eurostat提取的有关城市的数据看起来像这样:

TIME,CITIES,INDIC_UR,Value,Flag and Footnotes
2008,Germany,"Population on the 1st of January, total",82217837,
2008,Germany,"Population on the 1st of January, male",40274292,
2008,Germany,"Population on the 1st of January, female",41943545,
...
2010,Graz,"Population on the 1st of January, total",:,
2010,Graz,"Population on the 1st of January, male",:,
2010,Graz,"Population on the 1st of January, female",:,
2010,Graz,"Population on the 1st of January, 0-4 years, total",:,
2010,Graz,"Population on the 1st of January, 0-4 years, male",:,
...

我试图回答两个问题:

哪些城市/地区在2017年的人口最多?

哪些城市/地区在2010年到2016年间的相对增长最高?

使用这些库,我需要对数据进行一些清理,因为:表示缺失值,有些项目在文件中出现了两次。然后,需要将数据透视以分组区域,并将所有年份作为列。最后,需要计算一个“增长”列,并通过筛选“total”行并在正确的列上进行排序来得出答案。

在Python中使用pandas,这些操作很容易实现(也可以查看GitHub仓库中的笔记本):

data = pd.read_csv('urb_cpop1_1_Data.csv')
filtered = data.drop(data[data.Value == ":"].index)
filtered['key'] = filtered['CITIES'] + ':' + filtered['INDIC_UR']
filtered['Value'] = pd.to_numeric(filtered['Value'])
cities = filtered.pivot_table(index='key', columns='TIME', 
    values='Value', aggfunc="mean")# Top 10 cities by pop in 2017:
cities.filter(like='January, total',axis=0).
    sort_values(by=[2017], ascending=False).head(10)# Highest growth cities:
cities["growth"] = (cities[2016] / cities[2010] - 1) * 100
cities.filter(like='January, total',axis=0).
    sort_values(by=["growth"], ascending=False).head(10)

tablesaw

Tablesaw似乎是三者中开发最活跃的。GitHub账户非常活跃,由不同的开发者频繁提交代码。

2018年11月底更新:@ljw_larry向我展示了如何显着简化我的代码,并指出了最近版本中删除的一些限制。例如,它现在支持整型列、透视表格,而我错过了API的一个重要部分,它使得在特定值上进行过滤非常容易。

在内部,数据框架(称为“Table”)是包含数据的列对象的集合。向表格添加部分行不是很容易,你需要手动迭代所有列并添加空值(或为你没有值的所有列调用appendMissing())。如果Table有一个调用appendRow的方法,它将给予你一个新的、空的行对象,你可以在该行对象上调用setter,这将更好。

(在11月之前:)我没有找到一个很好的调用来执行透视操作,所以我通过调用Table上的forEach来实现自己的透视操作以迭代所有行,并在新框架中构建结果。不幸的是,没有一种方法可以轻松地过滤“total”类型的行,因此需要通过重新构建框架并手动进行过滤来完成。此外,没有一种方法可以直接添加计算的“增长”列。

joinery

Joinery是另一个开源的数据框架实现,它具有漂亮的流畅API,在文档的第一页中有特色。然而,joinery javadoc没有通常的侧面板,可以让你浏览包和其他类。我发现这很不方便。

Joinery确实有一个“透视”操作,但需要花费一些时间来弄清楚它是如何工作的,因为它没有任何文档。在透视之后,列名是Integer类型(年份),但库中的一些其他函数要求名称为String类型。按列降序排序的方法是在列名前加上'-',但sortBy("-2016")不起作用,因为字符串"2016"与整数2016不匹配。解决这个问题的方法是通过索引来访问列并将其变为负数(即sortBy(-10))。在其他许多地方也需要使用索引访问列。不幸的是,joinery没有提供一种很容易获得列索引的方法,因为它没有公开一个columnIndex(String colName)或类似的方法。

另一个小的问题是透视操作将城市和类型信息放入了一个特殊的行索引字段中,这不是常规表格单元格的一部分。这使得无法使用很好的函数构造(如select())对其进行过滤,需要使用forEach()遍历所有行来过滤所需的行。

与tablesaw不同,joinery有一个很好的API来添加计算的“增长”列。

morpheus

Morpheus是三个库中最功能齐全和最直接的API,我遇到的问题也最少。

我发现两个小缺点:透视操作不受本地支持(尽管我需要编写的代码仍然相对较短),对于原始列(即,IntegerDouble类型的列)不支持缺失值。所有带有缺失值的单元格都被设置为默认值(通常为0)。我仍然得到了我想要的结果,但在许多情况下,具有完全支持缺失值将更好。## datavec

我也简要尝试了datavec,它是deeplearning4j的一部分。它有一些很棒的特性:你可以在本地执行它的数据框转换,但它也支持Apache Spark作为执行器,因此当需要扩展时,你的代码很容易进行扩展。当我到达旋转步骤时,我停止了探索这个库,因为我认为使用内置转换不可能进行旋转。自定义转换代码似乎需要超过100行的代码,而不是我所寻找的几行lambda函数。

结论

这三个库都能够完成它们应该完成的任务,并且熟悉它们也不需要太长时间。最终,我最喜欢morpheus的API,而我创建的代码最短(在github仓库中的 TestMorpheus.java )。

2018年11月底更新: tablesaw的改进版本实际上是最好的,这也是我会使用的库。

然而,它仍然比所需的pandas代码长得多:50多行代码对比10行左右。

Python不仅更短,而且还有一个交互式笔记本体验可用。此刻很难为使用Java进行数据科学提出论据。也许kotlin可以改变这一点,像krangl这样的项目看起来很有前途。

译自:https://medium.com/@thijser/doing-cool-data-science-in-java-how-3-dataframe-libraries-stack-up-5e6ccb7b437

版权声明:本文内容由TeHub注册用户自发贡献,版权归原作者所有,TeHub社区不拥有其著作权,亦不承担相应法律责任。 如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

点赞(0)
收藏(0)
阿波
The minute I see you, I want your clothes gone!

评论(0)

添加评论