R语言 vs Python:数据分析哪家强? | 数据分析网 首页 分类阅读 行业资讯 大数据 统计学 数
时间: 2016-02-28来源:数据分析网
前景提要
摘要:这篇文章旨在更客观地看待这两门语言。我们会平行使用 Python 和R分析一个 数据集 ,展示两种语言在实现相同结果时需要使用什么样的代码。这让我们了解每种语言的优缺点,而不是猜想。在Dataquest,我们教授两种语言,并认为两者在数据科学工具箱中都占据各自的地位。
我们将会分析一个NBA数据集,包含运动员和他们在2013-2014赛季的表现,可以在 这里 下载这个数据集。我们展示Python和R的代码,同时做出一些解释和讨论。事不宜迟,现在就开始这场硬碰硬的对决吧!
读取CSV文件
R nba <- read.csv( "nba_2013.csv" )
Python import pandas nba = pandas.read_csv( "nba_2013.csv" )
上面的代码分别在两种语言中将包含2013-2014赛季NBA球员的数据的 nba_2013.csv 文件加载为变量 nba 。Python中实际的唯一不同是需要加载pandas库以使用Dataframe。Dataframe在R和Python中都可用,它是一个二维数组(矩阵),其中每列都可以是不同的数据类型。在完成这一步后,csv文件在两种语言中都加载为dataframe。
统计球员数量
R print(dim(nba)) [1] 481 31
Python print(nba.shape) (481, 31)
两者分别输出球员数量和数据列数量。我们有481行,或者说球员,和31列关于球员的数据。
查看数据的第一行
R print(head(nba, 1 )) player pos age bref_team_id 1 Quincy Acy SF 23 TOT [output truncated]
Python print(nba.head( 1 )) player pos age bref_team_id 0 Quincy Acy SF 23 TOT [output truncated]
它们几乎完全相同。两种语言都打印出数据的第一行,语法也非常类似。Python在这里更面向对象一些, head 是dataframe对象的一个方法,而R具有一个单独的 head 函数。当开始使用这些语言做分析时,这是一个共同的主题,可以看到Python更加面向对象而R更函数化。
计算每个指标的均值
让我们为每个指标计算均值。如你所见,数据列以类似 fg (field goals made)和 ast (assists)的名称命名。它们都是球员的赛季统计指标。如果想得到指标的完整说明,参阅 这里 。
R meanNoNA <- function (values){ mean(values, na.rm= TRUE ) } sapply(nba, meanNoNA) player NA pos NA age 26.5093555093555 bref_team_id NA [output truncated]
Python import numpy nba_numeric = nba._get_numeric_data() nba_numeric.apply(numpy,.mean, axis= 0 ) age 26.509356 g 53.253638 gs 25.571726 [output truncated]
这里有一些明显的分歧。在两种方法中,我们均在dataframe的列上应用了一个函数。在python中,如果我们在非数值列(例如球员姓名)上应用函数,会返回一个错误。要避免这种情况,我们只有在取平均值之前选择数值列。
在R中,对字符串列求均值会得到 NA ——not available(不可用)。然而,我们在取均值时需要确实忽略 NA (因此需要构建我们自己的函数)。否则类似 x3p. 这样的一些列的均值将会为 NA ,这一列代表三分球的比例。有些球员没有投出三分球,他们的百分比就是缺失的。如果我们直接使用R中的 mean 函数,就会得到 NA ,除非我们指定 na.rm=TRUE ,在计算均值时忽略缺失值。
绘制成对散点图
一个探索数据的常用方法是查看列与列之间有多相关。我们将会比较 ast , fg 和 trb 。
R library (GGally) ggpairs(nba[, c( "ast" , "fg" , "trb" )])
import seaborn as sns import matplotlib.pyplot as plt sns.pairplot(nba[[ "ast" , "fg" , "trb" ]]) plt.show()

我们会得到非常相似的两张图,但是可以看到R的数据科学生态中有许多较小的软件包( GGally 是最常用的R绘图包 ggplot2 的辅助包)和更多的通用可视化软件包。在Python中, matplotlib 是主要的绘图包, seaborn 是一个广泛用于matplotlib上的图层。Python中的可视化通常只有一种蛀牙哦的方法完成某件事,而R中可能有许多包支持不同的方法(例如,至少有半打绘制成对散点图的包)。
对球员聚类
另一个很好探索数据的方式是生成类别图。这将会显示哪些球员更相似。
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
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_
为了正确的聚类,我们移除了所有非数值列,以及包含缺失值的列。在R中,我们在每一列上应用一个函数,如果该列包含任何缺失值或不是数值,则删除它。接下来我们使用 cluster 包实施 k-means 聚类,在数据中发现5个簇。通过 set.seed 设置随机种子以使结果可复现。
在Python中,我们使用了主要的Python机器学习包 scikit-learn 拟合k-means模型并得到类别标签。数据准备的过程和R非常类似,但是用到了 get_numeric_data 和 dropna 方法。
绘制类别图
我们现在可以按类别绘制球员分布图以发现模式。首先使用 PCA 将数据降至2维,然后画图,用不同标记或深浅的点标志类别。 nba2d <- prcomp(nba[,goodCols], center= TRUE ) twoColumns <- nba2d$x[, 1 : 2 ] clusplot(twoColumns, labels)

Python 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中,我们通过聚类库中的函数 clusplot 函数绘图,使用内建函数 pccomp 实行PCA。
在Python中,我们使用scikit-learn库中的PCA类,使用matplotlib创建图形。
划分训练集和测试集
如果我们希望进行监督性机器学习,将数据划分为训练集和测试集是一个避免 过拟合 的好办法。
R trainRowCount <- floor( 0.8 * nrow(nba)) set.seed( 1 ) trainIndex <- sample( 1 :nrow(nba), trainRowCount) train <- nba[trainIndex,] test <- nba[-trainIndex,]
Python train = nba.sample(frac= 0.8 , random_state= 1 ) test = nba.loc[~nba.index.isin(train.index)]
你能注意到R有更多的 数据分析 内建函数,例如 floor , sample 和 set.seed ,这些函数在Python中通过第三方库被调用( math.floor , random.sample , random.seed )。在Python中,最新版本的pandas包含一个 sample 方法,返回对原始dataframe确定比例的随机抽样,这使得代码更加简洁。在R中,有很多包可以使抽样更容易,但是没有一个比使用内置 sample 函数更简洁。在两个例子中,我们都设置了随机种子以保证结果的可重复性。
一元线性回归
假设我们希望通过球员的得分预测其助攻次数。
R fit <- lm(ast ~ fg, data=train) predictions <- predict(fit, test)
Python from sklearn.linear_model import LinearRegression lr = LinearRegression() lr.fit(train[[ "fg" ]], train[ "ast" ]) predictions = lr.predict(test[[ "fg" ]])
Scikit-learn包含一个线性回归模型,我们可以通过它拟合并生成预测。R依赖于内建函数 lm 和 predict 。 predict 根据传递给它拟合模型的不同会表现出不同的行为,它可以被用于各种各样的模型。
计算模型统计量
R summary(fit) Call: lm(formula = ast ~ fg, data = train) Residuals: Min 1Q Median 3Q Max -228.26 -35.38 -11.45 11.99 559.61 [output truncated]
Python import statsmodels.formula.api as sm model = sm.ols(formula= 'ast ~ fga' , data=train) fitted = model.fit() print(fitted.summary()) OLS Regression Results ============================ Dep. Variable: ast R-squared: 0.568 Model: OLS Adj. R-squared: 0.567 [output truncated]
如果希望得到类似 R平方值 这样的模型统计量,在Python中需要比R多做一点。在R中,我们可以使用内建 summary 函数得到模型信息。在Python中,我们需要使用 statsmodels 包,这个包包含许多统计模型的Python实现。我们得到类似的结果,总体来说在Python中进行统计分析稍有点困难,一些R中存在的统计方法也没有存在于Python。
拟合一个随机森林模型
一元线性回归表现的不错,但是我们怀疑数据中可能存在 非线性 。因此,我们想要拟合一个 随机森林 模型。
R library (randomForest) predictorColumns <- c( "age" , "mp" , "fg" , "trb" , "stl" , "blk" ) rf <- randomForest(train[predictorColumns], train$ast, ntree= 100 ) predictions <- predict(rf, test[predictorColumns])
Python from sklearn.ensemble import RandomForestRegressor predictor_columns = [ "age" , "mp" , "fg" , "trb" , "stl" , "blk" ] rf = RandomForestRegressor(n_estimators= 100 , min_samples_leaf= 3 ) rf.fit(train[predictor_columns], train[ "ast" ]) predictions = rf.predict(test[predictor_columns])
这里主要的区别是R需要使用randomForest库实现算法,而Python中的scikit-learn直接内建其中。scikit-learn为许多不同的机器学习算法提供了统一的交互接口,在Python中每种算法通常只有一个主要的实现。而R中有许多包含单个算法较小的包,一般访问的方法并不一致。这导致算法更加的多样化(很多算法有多个实现,还有那些新问世的算法),但是只有一小部分是可用的。
计算误差
现在已经拟合了两个模型,下面让我们计算误差,使用 MSE
R mean((test[ "ast" ] - predictions)^ 2 ) 4573.86778567462
Python from sklearn.metrics import mean_squared_error mean_squared_error(test[ "ast" ], predictions) 4166.9202475632374
Python中的scikit-learn库包含我们可以使用的各种误差量度。在R中,可能有一些小的第三方库计算MSE,但是两种语言中手动计算它都很容易。误差的细微差异几乎可以肯定是由于参数调整造成的,并没什么关系。
下载一个网页
现在已经有了2013-2014赛季的NBA球员数据,让我们抓取一些额外数据补充它。为了节省时间,在 这里 看一场NBA总决赛的比分。
R library (RCurl) url <- "http://www.basketball-reference.com/boxscores/201506140GSW.html" page <- getURL(url) tc <- textConnection(page) data <- readLines(tc) close(tc)
Python import requests url = "http://www.basketball-reference.com/boxscores/201506140GSW.html" data = requests.get(url).content
Python中的 requests 包为所有的请求类型使用统一的API接口,下载网页非常容易。在R中, RCurl 提供稍微复杂方法发起请求。两者都把网页下载为字符串类型的数据。注:这在R中的下一步并不是必须,只是为了比较的原因。
抽取球员比分
现在我们已经下载了网页,需要处理它以抽取球员比分。
R library (rvest) page <- read_html(url) table <- html_nodes(page, ".stats_table" )[ 3 ] rows <- html_nodes(table, "tr" ) cells <- html_nodes(rows, "td a" ) teams <- html_text(cells) extractRow <- function (rows, i){ if (i == 1 ){ return } row <- rows[i] tag <- "td" if (i == 2 ){ tag <- "th" } items <- html_nodes(row, tag) html_text(items) } scrapeData <- function (team){ teamData <- html_nodes(page, paste( "#" ,team, "_basic" , sep= "" )) rows <- html_nodes(teamData, "tr" ) lapply(seq_along(rows), extractRow, rows=rows) } data <- lapply(teams, scrapeData)
Python from bs4 import BeautifulSoup import re soup = BeautifulSoup(data, 'html.parser' ) box_scores = [] for tag in soup.find_all(id=re.compile( "[A-Z]{3,}_basic" )): rows = [] for i, row in enumerate(tag.find_all( "tr" )): if i == 0 : continue elif i == 1 : tag = "th" else : tag = "td" row_data = [item.get_text() for item in row.find_all(tag)] rows.append(row_data) box_scores.append(rows)
这将创建一个包含两个列表的列表,第一个是 CLE 的比分,第二个是 GSW 的比分。两个都有标题,以及每个球员和他们的比赛统计。我们现在不会将其转换为更多的训练数据,但是如果需要把它们加入 nba dataframe,转换可以很容易地完成。
R代码比Python更复杂,因为它没有一个方便的方式使用正则表达式选择内容,因此我们不得不做额外的处理以从HTML中得到队伍名称。R也不鼓励使用 for 循环,支持沿向量应用函数。我们使用 lapply 做到这一点,但由于需要处理的每一行都因是否是标题而异,需要传递保留项的索引和整个 rows 列表给函数。
我们使用 rvest ,一个广泛使用的新R网络抓取包实现抽取数据,注意这里可以直接传递url给rvest,因此上一步在R中并不是必须的。
在Python中,我们使用了 BeautifulSoup ,一个最常用的web抓取包。它让我们可以在标签间循环,并以一种直接的方式构建列表的列表。
结论
我们已经看到了如何使用R和Python分析一个数据集。还有很多任务没有深入,例如保存和分享分析结果,测试,确保生产就绪,以及构建更多的可视化。我们会在近期继续探讨这些,从而得到更明确的结论。现在,下面是一些能够得到的:
R更加函数化,Python更面向对象
就像我们在 lm , predict 和其他函数中看到的那样,R用函数完成大部分工作。对比Python中的`LinearRegression类,还有dataframe的sample方法。
R包含更多的数据分析内建功能,Python依赖于第三方软件包。
当我们查看汇总统计量时,在R中可以直接使用 summary 内建函数,但是Python中必须依靠statsmodels包。dataframe是R内置的结构,而在Python中由 pandas 包引入。
Python拥有“主要的”数据分析包,R拥有由较小的包组成的更大的生态系统
在Python中,我们可以使用scikit-learn完成线性回归,随机森林和许多其他任务。它提供了一致的API,并很好的维护。在R中,我们有多种多样的包,但是也更加碎片化和不一致(线性回归是内置的 lm , randomForest 是单独的包,等等)。
总体上R有更多的统计支持
R是作为统计语言被构建的,它也显示了这一点。Python中的 statsmodels 和其他软件包提供了统计方法的大部分实现,但是R的生态系统要大的多。
Python中完成非统计任务通常更加直接
有了类似BeautifulSoup和request这样良好维护的软件包,Python中的网页抓取远易于R。这种说法也适于我们还未关注的其他任务,例如保存数据库,部署web服务器或运行复杂的工作流。
数据分析工作流在两者之间有许多相似之处
R和Python之间有一些互相启发的地方(pandas的Dataframe受到R中dataframe的影响,rvest包来自BeautifulSoup的启发),两者的生态系统都在不断发展壮大,对两种语言中许多共同的任务来说,语法和实现都是非常相似的。
总结
在 Dataquest ,我们首先教授Python,但是最近也加入了R的课程。我们看到这两种语言是互补的,虽然Python在更多领域更强大,但R是一种高效的语言。它可以作为Python在数据探索和统计等领域的补充,或者你惟一的数据分析工具。正如本篇文章中所显示的,两种语言有许多相似的语法和实现方法,你不能在一个或另一个,或者两者中出错。 Vik Paruchuri 原文链接
本文采用「CC BY-SA 4.0 CN」协议转载自互联网、仅供学习交流,内容版权归原作者所有,如涉作品、版权和其他问题请给「 我们 」留言处理。

科技资讯:

科技学院:

科技百科:

科技书籍:

网站大全:

软件大全:

热门排行