在真实的数据科学世界里,我们会有两个极端,一个是业务,一个是工程。偏向业务的数据科学被称为数据分析(Data Analysis),也就是A型数据科学。偏向工程的数据科学被称为数据构建(Data Building),也就是B型数据科学。
从工具上来看,按由业务到工程的顺序,这个两条是:EXCEL >> R >> Python >> Scala
在实际工作中,对于小数据集的简单分析来说,使用EXCEL绝对是最佳选择。当我们需要更多复杂的统计分析和数据处理时,我们就需要转移到 Python 和 R 上。在确定工程实施和大数据集操作时,我们就需要依赖 Scala 的静态类型等工程方法构建完整的数据分析系统。
Scala 和 Excel 是两个极端,对于大多数创业公司而言,我们没有足够多的人手来实现专业化的分工,更多情况下,我们会在 Python 和 R 上花费更多的时间同时完成数据分析(A型)和数据构建(B型)的工作。而许多人也对 Python 和 R 的交叉使用存在疑惑,所以本文将从实践角度对 Python 和 R 中做了一个详细的比较。
网络爬虫/抓取:尽管 rvest 已经让 R 的网络爬虫/抓取变得容易,但 Python 的 beautifulsoup 和 Scrapy 更加成熟、功能更强大,结合django-scrapy我们可以很快的构建一个定制化的爬虫管理系统。
连接数据库: R 提供了许多连接数据库的选择,但 Python 只用 sqlachemy 通过ORM的方式,一个包就解决了多种数据库连接的问题,且在生产环境中广泛使用。Python由于支持占位符操作,在拼接SQL语句时也更加方便。
内容管理系统:基于Django,Python可以快速通过ORM建立数据库、后台管理系统,而R中的 Shiny 的鉴权功能暂时还需要付费使用。
API构建:通过Tornado这个标准的网络处理库,Python也可以快速实现轻量级的API,而R则较为复杂。
统计分析: 尽管 Python 里 Scipy、Pandas、statsmodels 提供了一系列统计工具 ,R 本身是专门为统计分析应用建立的,所以拥有更多此类工具。
互动式图表/面板: 近来 bokeh、plotly、 intuitics 将 Python 的图形功能扩展到了网页浏览器,甚至我们可以用tornado+d3来进一步定制可视化页面,但 R 的 shiny 和 shiny dashboard 速度更快,所需代码更少。
此外,当今数据分析团队拥有许多技能,选择哪种语言实际上基于背景知识和经验。对于一些应用,尤其是原型设计和开发类,工作人员使用已经熟悉的工具会比较快速。
接着,我们将通过下面几个方面,对Python 和 R 的数据流编程做出一个详细的对比。
参数传递
数据读取
基本数据结构对照
矩阵转化
矩阵计算
数据操作
Python/R 都可以通过命令行的方式和其他语言做交互,通过命令行而不是直接调用某个类或方法可以更好地降低耦合性,在提高团队协作的效率。
参数传递 | Python | R |
---|---|---|
命令行输入 | Python path/to/myscript.py arg1 arg2 arg3 | Rscript path/to/myscript.R arg1 arg2 arg3 |
脚本识别 | import sys my_args = sys.argv | myArgs <- commandArgs(trailingOnly = TRUE) |
对于数据传输与解析,我们首推的格式是csv,因为一方面,csv格式的读写解析都可以通过 Python 和 R 的原生函数完成,不需要再安装其他包。另一方面,csv格式可以很快的转化为 data frame 格式,而data frame 格式是数据流分析的核心。
不过,实际情况中,我们需要传输一些非结构化的数据,这时候就必须用到 JSNO 或者 YAML。
数据传输与解析 | Python | R |
---|---|---|
CSV(原生) | csv | read.csv |
CSV(优化) | pandas.read_csv("nba_2013.csv") | data.table::fread("nba_2013.csv") |
JSON | json(原生) | jsonlite |
YAML | PyYAML | yaml |
由于是从科学计算的角度出发,R 中的数据结构非常的简单,主要包括 向量(一维)、多维数组(二维时为矩阵)、列表(非结构化数据)、数据框(结构化数据)。而 Python 则包含更丰富的数据结构来实现数据更精准的访问和内存控制,多维数组(可读写、有序)、元组(只读、有序)、集合(唯一、无序)、字典(Key-Value)等等。
基本数据结构 | Python | R |
---|---|---|
数组 | list:[1,'a'] | :array:array(c(1,"a"),2) |
Key-Value(非结构化数据) | 字典:["a":1] | lists |
数据框(结构化数据) | dataframe | data.frame |
实际上,Python(numpy) 和 R中的矩阵都是通过一个多维数组(ndarray)实现的。
矩阵转化 | Pyhton | R |
---|---|---|
维度 | data.shape | dim(data) |
转为向量 | data.flatten(1) | as.vector(data) |
转为矩阵 | np.array([[1,2,3],[3,2,1]]) | matrix(c(1,2,3,3,2,1),nrow=2,byrow=T) |
转置 | data.T | t(data) |
矩阵变形 | data.reshape(1,np.prod(data.shape)) | matrix(data,ncol=nrow(data)*ncol(data)) |
矩阵按行拼接 | np.r_[A,B] | rbind(A,B) |
矩阵按列拼接 | np.c_[A,B] | cbind(A,B) |
矩阵计算 | Pyhton | R |
---|---|---|
矩阵乘法 | np.dot(A,B) | A %*% B |
矩阵幂指 | np.power(A,3) | A^3 |
全零矩阵 | np.zeros((3,3)) | matrix(0,nrow=3,ncol=3) |
矩阵求逆 | np.linalg.inv(A) | solve(A) |
协方差 | np.cov(A,B) | cov(A,B) |
特征值 | np.linalg.eig(A)[0] | eigen(A)$values |
特征向量 | np.linalg.eig(A)[1] | eigen(A)$vectors |
参考 R 中的 data frame 结构,Python 的 Pandas包也实现了类似的 data frame 数据结构。现在,为了加强数据框的操作,R 中更是演进出了 data table 格式(简称dt),这种格式以 dt[where,select,group by] 的形式支持类似SQL的语法。
数据框操作 | Python | R |
---|---|---|
按Factor的Select操作 | df[['a', 'c']] | dt[,.(a,c),] |
按Index的Select操作 | df.iloc[:,1:2] | dt[,1:2,with=FALSE] |
按Index的Filter操作 | df[1:2] | dt[1:2] |
groupby分组操作 | df.groupby(['a','b'])[['c','d']].mean() | aggregate(x=dt[, c("v1", "v2")], by=list(mydt2$by1, mydt2$by2), FUN = mean) |
%in% 匹配操作 返回T/F | pd.Series(np.arange(5),dtype=np.float32).isin([2, 4]) | 0:4 %in% c(2,4) |
match 匹配操作 返回Index | pd.Series(pd.match(pd.Series(np.arange(5),dtype=np.float32),[2,4],np.nan)) | match(0:4, c(2,4)) |
tapply | df.pivot_table(values='a', columns='c', aggfunc=np.max) | tapply(dt$a,dt$c,max)#其中dt$a是numeric,dt$c是nominal |
查询操作 | df[df.a <= df.b] | dt[ a<=b ] |
with操作 | pd.DataFrame({'a': np.random.randn(10), 'b': np.random.randn(10)}).eval('a + b') | with(dt,a + b) |
plyr操作 | df.groupby(['month','week']).agg([np.mean, np.std]) | ddply(dt, .(month, week), summarize,mean = round(mean(x), 2),sd = round(sd(x), 2)) |
多维数组融合 | pd.DataFrame([tuple(list(x)+[val]) for x, val in np.ndenumerate(np.array(list(range(1,24))+[np.NAN]).reshape(2,3,4))]) | data.frame(melt(array(c(1:23, NA), c(2,3,4)))) |
多维列表融合 | pd.DataFrame(list(enumerate(list(range(1,5))+[np.NAN]))) | data.frame(melt(as.list(c(1:4, NA)))) |
数据框融合 | pd.melt(pd.DataFrame({'first' : ['John', 'Mary'],'last' : ['Doe', 'Bo'],'height' : [5.5, 6.0],'weight' : [130, 150]}), id_vars=['first', 'last']) | melt(data.frame(first = c('John', 'Mary'),last = c('Doe', 'Bo'),height = c(5.5, 6.0),weight = c(130, 150), id=c("first", "last")) |
数据透视表 pivot table | pd.pivot_table(pd.melt(pd.DataFrame({ 'x': np.random.uniform(1., 168., 12), 'y': np.random.uniform(7., 334., 12), 'z': np.random.uniform(1.7, 20.7, 12), 'month': [5,6,7] 4, 'week': [1,2] 6}), id_vars=['month', 'week']), values='value', index=['variable','week'],columns=['month'], aggfunc=np.mean) | acast(melt(data.frame(x = runif(12, 1, 168),y = runif(12, 7, 334),z = runif(12, 1.7, 20.7),month = rep(c(5,6,7),4),week = rep(c(1,2), 6)), id=c("month", "week")), week ~ month ~ variable, mean) |
连续型数值因子分类 | pd.cut(pd.Series([1,2,3,4,5,6]), 3) | cut(c(1,2,3,4,5,6), 3) |
名义型因子分类 | pd.Series([1,2,3,2,2,3]).astype("category") | factor(c(1,2,3,2,2,3)) |
(df .groupby(['a', 'b', 'c'], as_index=False) .agg({'d': sum, 'e': mean, 'f', np.std}) .assign(g=lambda x: x.a / x.c) .query("g > 0.05") .merge(df2, on='a'))
flights %>% group_by(year, month, day) %>% select(arr_delay, dep_delay) summarise( arr = mean(arr_delay, na.rm = TRUE), dep = mean(dep_delay, na.rm = TRUE)) %>% filter(arr > 30 | dep > 30)
对比数据相关性是数据探索常用的一种方法,下面是Python和R的对比。
import seaborn as sns import matplotlib.pyplot as plt sns.pairplot(nba[["ast", "fg", "trb"]]) plt.show()
library(GGally) ggpairs(nba[,c("ast", "fg", "trb")])
虽然我们最终得到了类似的图形,这里R中 GGally
是依赖于 ggplot2
,而Python则是在 matplotlib
的基础上结合 Seaborn
,除了 GGally
在R中我们还有很多其他的类似方法来实现对比制图,显然R中的绘图有更完善的生态系统。
这里以K-means为例,为了方便聚类,我们将非数值型或者有确实数据的列排除在外。
from sklearn.cluster import KMeans kmeans_model = KMeans(n_clusters=5, random_state=1) good_columns = nba._get_numeric_data().dropna(axis=1) kmeans_model.fit(good_columns) labels = kmeans_model.labels_ from sklearn.decomposition import PCA pca_2 = PCA(2) plot_columns = pca_2.fit_transform(good_columns) plt.scatter(x=plot_columns[:,0], y=plot_columns[:,1], c=labels) plt.show()
library(cluster) set.seed(1) isGoodCol <- function(col){ sum(is.na(col)) == 0 && is.numeric(col) } goodCols <- sapply(nba, isGoodCol) clusters <- kmeans(nba[,goodCols], centers=5) labels <- clusters$cluster nba2d <- prcomp(nba[,goodCols], center=TRUE) twoColumns <- nba2d$x[,1:2] clusplot(twoColumns, labels)
Python 的 pandas 从 R 中偷师 dataframes,R 中的 rvest 则借鉴了 Python 的 BeautifulSoup,我们可以看出两种语言在一定程度上存在的互补性,通常,我们认为 Python 比 R 在泛型编程上更有优势,而 R 在数据探索、统计分析是一种更高效的独立数据分析工具。所以说,同时学会Python和R这两把刷子才是数据科学的王道。
pandas doucumentation: Comparison with R / R libraries
Comparison – R vs. Python: head to head data analysis
Hacker News: Comparison – R vs. Python
Quora: How does R compare with pandas?
yhat: R and pandas and what I've learned about each
Why are pandas merges in python faster than data.table merges in R?
Python和R科学计算操作速查表
知乎:R 和 Python (numpy scipy pandas) 用于统计学分析,哪个更好?
作为分享主义者(sharism),本人所有互联网发布的图文均遵从CC版权,转载请保留作者信息并注明作者 Harry Zhu 的 FinanceR专栏: https://segmentfault.com/blog/harryprinc... ,如果涉及源代码请注明GitHub地址: https://github.com/harryprince 。微信号: harryzhustudio
商业使用请联系作者。