[原]深入对比数据科学工具箱:Python3 和 R 之争[2020版]

python  R - Explore - Google Trends.png

概述

R 和 Python2/Python3 在过去十年(Pandas问世后)的数据科学领域持续着激烈的竞争,随着时间的推移竞争格局也从混沌走向清晰。

R 从诞生开始就继承了 S 语言的统计特性,经历了野蛮生长,2009 年 ggplot2 和 data.table 的横空出世大幅提升数据可视分析的效率,极大冲击了数据科学早期市场,要知道当时数据科学还主要被商业软件 Excel、SAS 和 Matlab 所垄断。R语言作为数据科学开源软件的先驱,多个商业应用领域不断进化,贝叶斯、空间分析、网络分析、时序分析、生存分析等在代码库 CRAN 和 GitHub 上开始快速增长,直到 2015年 Revolution R 被 Microsoft 公司收购达到顶峰。

Python 原本是一种胶水语言,在Web开发、嵌入式开发、运维测试等领域使用较为广泛,在数据科学领域运用并不广泛。然而,自 2015年大数据和深度学习的人工智能革命起,Python 中的两大开源框架 PySpark 和 Tensorflow 开始大放异彩,全民学习 Python 的热情也随水涨船高,Python 成功实现了数据科学领域的逆袭。

生态对比

download (2).png

Domain Python3 R
基础数据处理 Pandas/Dplython Tidyverse/Dplyr
基础数据处理 (py)datatable data.table
并行计算(数据密集) Koalas/PySpark Sparklyr/SparkR
并行计算(计算密集) Dask/Modin Disk.frame
网络挖掘 Networkx/Graph-tool Tidygraph
地理挖掘 Geopandas/Rasterio Sf/Raster
时序挖掘 Sktime/Backtrader Fable/Quantstrat
图像处理 OpenCV magick
文本处理 SpaCy tidytext
基础统计工具 Statsmodels tidymodel
贝叶斯统计 PyMC3/PyStan Brms/Rstanarm/Shinystan
机器学习 Sklearn Mlr
深度学习 Tensorflow/Mxnet Tensorflow/Mxnet
强化学习 RLlib/Gym ReinforcementLearning
仿真建模 Simpy Simmer
运筹优化 Cvxpylayers/Ortools/Pyomo CVXR/ompr
原型开发 Dash/Django Shiny/Flexdashboard
数据探索 Plotly/Matplotlib/Plotnine Plotly/Ggplot2/Esquisse

1. 数据处理工具对比

数据处理工具目前大概分为两个方向:1. 高性能单机 2. 分布式处理

自2016年以来,Python 和 R 的数据处理工具之间不断融合,互相学习,取长补短,易用性和生产力也已经不相上下。基本形成了 pandas(Python)、tidyverse(R) 为核心的两大前端语法体系,后端计算引擎则包含 Spark,Dask,data.table 等。

单机

Pandas 篇

在单机处理方面,Python 形成了以Pandas为核心的主流基础数据流处理框架,囊括了从数据IO、CRUD、数据透视、数据可视的全流程,并且通过 Dplython 可实现类似于 R 中 Tidyverse 的管道操作语法。举例如下:

尝试读取iris数据集合,并且做分组计数:

Python 版本

import pandas as pd
from Dplython import *

df = pd.read_csv("~/tmp.csv")

res = df >>\
select(X.Sepal_Length,X.Species) >>\
group_by(X.Species)>>\
summarize(cnt = X.Species.count())

res.plot()

R 版本

library(tidyverse)

df = readr::read_csv("~/tmp.csv")

res = df %>%
select(Sepal.Length,Species) %>%
group_by(Species) %>%
summarise(cnt = n()) %>% 
plot()
Data.table 篇

单机数据处理的另外一个重要流派便是以计算性能所闻名的 data.table 体系,经过10余年的不断优化,基于 C 开发的 data.table 在单机数据处理的性能和稳定性上完爆大部分框架。下面是 data.table 最新性能评测,在GroupBy算子处理 50G 数据的性能对比,data.table 以 123s 的成绩完爆同类工具。 在评测中我们看到原始 dplyr 的性能相对 data.table 比慢了 20倍(得益于 data.table 处理数据过程内存拷贝最小化)。

image.png

目前 data.table 开发了 data.table(R) 和 datatable(Python) 两个版本, 其中 data.table(R) 性能有微弱优势。同样以 iris 的例子做对比:

Python 版本

import datatable as dt
df = dt.fread("tmp.csv")
df[:, dt.count(), dt.by("Species")]

# | **Species  count**
#\-- + ---------- \-----
#0 | setosa  50
#1 | versicolor  50
#2 | virginica 50

R 版本

library(data.table)
df = data.table::fread("tmp.csv")
df[,.N, by = .(Species) ]
#      Species  N
#1:     setosa 50
#2: versicolor 50
#3:  virginica 50

不过有不少用户反映 data.table 的[where,select,group_by]语法没有 dplyr 容易上手。有幸的是,在 R 中通过 Hadley 开发的 dtplyr 工具,我们可以直接将 data.table 作为 dplyr 的后端计算引擎,免除切换框架的烦恼。

举例 R 代码:

library(data.table)
library(dtplyr)
library(dplyr, warn.conflicts = FALSE)

iris %>%
lazy_dt() %>%
select(Sepal.Length,Species) %>%
group_by(Species) %>%
summarise(cnt = n()) 

#      Species  N
#1:     setosa 50
#2: versicolor 50
#3:  virginica 50
分布式
PySpark 篇

在分布式处理方面,PySpark 框架虽然在易用性上多为人诟病,但得益于先发优势和广大的码农群众基础,已经成为了最主流的分布式数据处理框架,涵盖了从数据IO、SQL、UDF定义、数据透视、模型训练的全流程,并且通过 Koalas 可实现类似于 R 中 Sparklyr 的管道操作语法,让用户只需掌握 Pandas 而不用学习RDD就可以实现数据的操作。

这里依然以 iris 分组计数为例:

Python 版本

from pyspark import SparkConf, SparkContext
conf = SparkConf()
conf.set('spark.executor.memory', '2g')
# Koalas 自动复用 Spark 配置
SparkContext(conf=conf)

import pandas as pd
import databricks.koalas as ks


df = pd.read_csv("tmp.csv")
sdf = ks.from_pandas(df)

sdf[['Sepal.Length','Species']].\
  groupby('Species').\
  count()
#         Sepal.Length
# Species
# setosa     50
# versicolor 50
# virginica  50

R 版本

library(sparklyr)
sc = spark_connect("localhost",conf = spark_conf())

sdf = copy_to(sc,iris, name = "iris") # 复制数据到 spark 集群

sdf %>% 
select(Sepal_Length,Species) %>%
group_by(Species) %>%
summarise(cnt = n()) %>%
collect()
Disk.frame 篇

前文提到过,数据处理另外一个流派是 data.table,基于 data.table 之上形成的分布式处理框架就是 disk.frame ,disk.frame 和 Spark 的最大区别就是,disk.frame 优先解决的是计算密集型的复杂模型运算任务,让数据跟随计算;而 Spark 因为使用的是 Map-Reduce 模型,计算跟随数据,所以更擅长数据密集型的简单ETL运算任务。

也正是由于计算模型的不同,disk.frame 可以直接运行所有本地已经安装的模型库,不需要做额外的打包处理。而 PySpark 同常还需要将相关的Python依赖包打到conda环境的zip文件中,操作过程相对麻烦。

所以,相对而言,尤其在数据量超大的模型训练过程中,处理若干个csv文件夹,disk.frame 是非常顺手且快如闪电!因此,disk.frame 尤其适合应用于强化学习、图模型、仿真计算等计算密集型任务。

有幸的是,在 Python 世界中有两个和 disk.frame 类似的工具,一个是 Dask,另外一个是 Modin。一方面,他们都提供类似 Pandas 的数据操作语法,另一方面,这两个项目也在不断融合。目前,相对而言 Dask 更加成熟一些。

依然以 iris 的例子做比较:

R 版本:

library(disk.frame)
setup_disk.frame()

# this allows large datasets to be transferred between sessions
options(future.globals.maxSize = Inf)

path_to_data <- "path/to/data/"

ddf <- csv_to_disk.frame(
  paste0(path_to_data, "combined.csv"), 
  outdir = paste0(path_to_data, "combined.df"),
  in_chunk_size = 2e6,
  backend = "LaF")

ddf %>%
select(Sepal_Length,Species) %>%
group_by(Species) %>%
summarise(cnt = n()) %>%
collect()

Python 版本


import dask.dataframe as dd

ddf = dd.read_csv("tmp.csv")

ddf[['Sepal.Length','Species']].\
  groupby('Species').\
  count()

2. 领域数据挖掘对比

PyDs - Google Slides (3).png

领域数据挖掘按照数据维度整体上可以分为 1. 序列数据挖掘 2. 空间数据挖掘 3. 网络数据挖掘

自2016年以来,在领域数据挖掘中也承袭了 pandas(Python)、tidyverse(R) 为核心的两大前端语法体系,在此基础上根据不同领域对 data.frame 结构进行改造,以便于数据分析的开展。

序列数据挖掘

tidyverts 篇

自然世界中最简单的数据便是序列数据,万物皆在时序维度上留下痕迹。就时序挖掘而言,自 2016年以来,在 R 中形成了以 Tidyverts 为核心的主流时序数据处理框架,囊括了数据IO、时序补全、时间索引(tsibble)、时序建模(fable)、时序半自动可视化(feasts)的全流程,其中时序建模取代了经典工具 forecast,并全面覆盖了经典统计(autoarima)、贝叶斯推断(prophet)、深度学习(keras)等多种方法,全面替代。

Python 相对而言在时序建模方面起步较晚,且较少应用于宏观经济数据分析,多应用于微观行为建模,目前处于 sktime 为主要工具,tsfresh、gluon-ts、pmdarima、prophet 等多种工具分散的局面,生态还在逐渐成熟过程中,借助于 Tensorflow 和 LSTM 的东风正在快速崛起。

这里以主要介绍 R 中带有时间索引的 tsibble 数据结构。tsibble = ts + tibble, 利用时序数据特点,它将 data.frame 中引入 key 和 group 的概念,并且通过时间索引,大幅提升计算的效率,支持 sliding window, fixed window, forever window 等多种窗口函数

R 版本


library(dplyr)
library(lubridate)
library(tsibble)
weather_tsbl <- nycflights13::weather %>% 
  select(origin, time_hour, temp, humid, precip) %>%
as_tsibble(key = origin)

weather_tsbl %>%
  group_by_key() %>%
  index_by(date = ~ as_date(.)) %>% 
  summarise(
    temp_high = max(temp, na.rm = TRUE),
    temp_low = min(temp, na.rm = TRUE)
  )

#> # A tsibble: 1,092 x 4 [1D]
#> # Key:       origin [3]
#>   origin date       temp_high temp_low
#>   <chr>  <date>         <dbl>    <dbl>
#> 1 EWR    2013-01-01      41       28.0
#> 2 EWR    2013-01-02      34.0     24.1
#> 3 EWR    2013-01-03      34.0     26.1
#> 4 EWR    2013-01-04      39.9     28.9
#> 5 EWR    2013-01-05      44.1     32  
#> # … with 1,087 more rows
tidytext 篇
library(tidytext)
library(dplyr)

text_df <- c("Because I could not stop for Death -",
          "He kindly stopped for me -",
          "The Carriage held but just Ourselves -",
          "and Immortality") %>%
          tibble(line = 1:4, text = .)

text_df %>%
  unnest_tokens(word, text)

## # A tibble: 20 x 2
##     line word   
##    <int> <chr>  
##  1     1 because
##  2     1 i      
##  3     1 could  
##  4     1 not    
##  5     1 stop   
##  6     1 for    
##  7     1 death  
##  8     2 he     
##  9     2 kindly 
## 10     2 stopped
## # … with 10 more rows

spaCy

import spacy from dframcy
import DframCy 
nlp = spacy.load('en_core_web_sm') 
dframcy = DframCy(nlp) 
doc = dframcy.nlp(u'Apple is looking at buying U.K. startup for $1 billion') 
annotation_dataframe = dframcy.to_dataframe(doc)

空间数据挖掘

sf 篇

geopandas 对比

CNN 篇

网络数据挖掘

tidygraph 篇

networkx 对比

GNN 篇

总结

  • R 社区活跃度有所下降,但生产能力的弱项在不断提升。
  • Python2 逐渐放弃维护。
  • Python3 取代 Python2 和 R 成为新一代人工智能主流编程语言。

参考资料

阅读 1.8k

推荐阅读
FinanceR
用户专栏

循环写作,持续更新,形成闭环,贵在坚持

1006 人关注
60 篇文章
专栏主页
目录