[原]深刻對比數據科學工具箱:Python和R之爭[2016版]

clipboard.png

概述

在真實的數據科學世界裏,咱們會有兩個極端,一個是業務,一個是工程。偏向業務的數據科學被稱爲數據分析(Data Analysis),也就是A型數據科學。偏向工程的數據科學被稱爲數據構建(Data Building),也就是B型數據科學。html

從工具上來看,按由業務到工程的順序,這個兩條是:EXCEL >> R >> Python >> Scalapython

在實際工做中,對於小數據集的簡單分析來講,使用EXCEL絕對是最佳選擇。當咱們須要更多複雜的統計分析和數據處理時,咱們就須要轉移到 Python 和 R 上。在肯定工程實施和大數據集操做時,咱們就須要依賴 Scala 的靜態類型等工程方法構建完整的數據分析系統。git

Scala 和 Excel 是兩個極端,對於大多數創業公司而言,咱們沒有足夠多的人手來實現專業化的分工,更多狀況下,咱們會在 Python 和 R 上花費更多的時間同時完成數據分析(A型)和數據構建(B型)的工做。而許多人也對 Python 和 R 的交叉使用存在疑惑,因此本文將從實踐角度對 Python 和 R 中作了一個詳細的比較。github

應用場景對比

應用Python的場景

  • 網絡爬蟲/抓取:儘管 rvest 已經讓 R 的網絡爬蟲/抓取變得容易,但 Python 的 beautifulsoup 和 Scrapy 更加成熟、功能更強大,結合django-scrapy咱們能夠很快的構建一個定製化的爬蟲管理系統。
  • 鏈接數據庫: R 提供了許多鏈接數據庫的選擇,但 Python 只用 sqlachemy 經過ORM的方式,一個包就解決了多種數據庫鏈接的問題,且在生產環境中普遍使用。Python因爲支持佔位符操做,在拼接SQL語句時也更加方便。
  • 內容管理系統:基於Django,Python能夠快速經過ORM創建數據庫、後臺管理系統,而R

中的 Shiny 的鑑權功能暫時還須要付費使用。sql

  • API構建:經過Tornado這個標準的網絡處理庫,Python也能夠快速實現輕量級的API,而R則較爲複雜。

應用R的場景

  • 統計分析: 儘管 Python 裏 Scipy、Pandas、statsmodels 提供了一系列統計工具 ,R 自己是專門爲統計分析應用創建的,因此擁有更多此類工具。
  • 互動式圖表/面板: 近來 bokeh、plotly、 intuitics 將 Python 的圖形功能擴展到了網頁瀏覽器,甚至咱們能夠用tornado+d3來進一步定製可視化頁面,但 R 的 shiny 和 shiny dashboard 速度更快,所需代碼更少。

此外,當今數據分析團隊擁有許多技能,選擇哪一種語言實際上基於背景知識和經驗。對於一些應用,尤爲是原型設計和開發類,工做人員使用已經熟悉的工具會比較快速。數據庫

數據流編程對比

接着,咱們將經過下面幾個方面,對Python 和 R 的數據流編程作出一個詳細的對比。django

  1. 參數傳遞
  2. 數據讀取
  3. 基本數據結構對照
  4. 矩陣轉化
  5. 矩陣計算
  6. 數據操做

參數傳遞

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 格式是數據流分析的核心。json

不過,實際狀況中,咱們須要傳輸一些非結構化的數據,這時候就必須用到 JSNO 或者 YAML。segmentfault

數據傳輸與解析 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 則包含更豐富的數據結構來實現數據更精準的訪問和內存控制,多維數組(可讀寫、有序)、元組(只讀、有序)、集合(惟1、無序)、字典(Key-Value)等等。

基本數據結構 Python R
數組 list:[1,'a'] :array:array(c(1,"a"),2)
Key-Value(非結構化數據) 字典:["a":1] lists
數據框(結構化數據) dataframe data.frame

Python dict 操做:dict["key"] 或者 dict.get("key","default_return")
R list 操做: list["key"] 或者 list$key

R 中數據結構轉化(plyr) list data frame array
list llply() ldply() laply()
data frame dlply() ddply() daply()
array alply() adply() aaply()

MapReduce

Python R
map Map
reduce Reduce
filter filter

矩陣操做

實際上,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))

數據流編程對比的示例

Python 的 Pandas 中的管道操做
(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'))
R 的 dplyr 中的管道操做
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的對比。

Python
import seaborn as sns
import matplotlib.pyplot as plt
sns.pairplot(nba[["ast", "fg", "trb"]])
plt.show()

R
library(GGally)
ggpairs(nba[,c("ast", "fg", "trb")])

雖然咱們最終獲得了相似的圖形,這裏R中GGally是依賴於ggplot2,而Python則是在matplotlib的基礎上結合Seaborn,除了GGally在R中咱們還有不少其餘的相似方法來實現對比製圖,顯然R中的繪圖有更完善的生態系統。

繪製聚類效果圖

這裏以K-means爲例,爲了方便聚類,咱們將非數值型或者有確實數據的列排除在外。

Python
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()

R
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
import numpy as np
xx = np.zeros(100000000)
%timeit xx[:] = 1
The slowest run took 9.29 times longer than the fastest. This could mean that an intermediate result is being cached 
1 loops, best of 3: 111 ms per loop
R
xx <- rep(0, 100000000)
system.time(xx[] <- 1)
user  system elapsed 
  1.326   0.103   1.433

顯然這裏 R 1.326的成績 比 Python 的 Numpy 3:111 的速度快了很多。

事實上,如今 R 和 Python 的數據操做的速度已經被優化得旗鼓至關了。下面是R中的 data.table、dplyr 與 Python 中的 pandas 的數據操做性能對比:

我曾經用data.table和pandas分別讀取過一個600萬行的IOT數據,反覆10次,data.table以平均10s的成績賽過了pandas平均15s的成績,因此在IO上我傾向於選擇使用data.table來處理大數據,而後餵給spark和hadoop進行進一步的分佈式處理。

結論

Python 的 pandas 從 R 中偷師 dataframes,R 中的 rvest 則借鑑了 Python 的 BeautifulSoup,咱們能夠看出兩種語言在必定程度上存在的互補性,一般,咱們認爲 Python 比 R 在泛型編程上更有優點,而 R 在數據探索、統計分析是一種更高效的獨立數據分析工具。因此說,同時學會Python和R這兩把刷子纔是數據科學的王道。

參考資料

做爲分享主義者(sharism),本人全部互聯網發佈的圖文均聽從CC版權,轉載請保留做者信息並註明做者 Harry Zhu 的 FinanceR專欄: https://segmentfault.com/blog...,若是涉及源代碼請註明GitHub地址: https://github.com/harryprince。微信號: harryzhustudio 商業使用請聯繫做者。
相關文章
相關標籤/搜索