Python与Stata, R, SAS, SQL在数据处理上的比较, 含code及细致讲解
凡是搞计量经济的,都关注这个号了
邮箱:econometrics666@sina.cn
前些日,咱们圈子引荐了①“实证研究中用到的200篇文章, 社科学者常备toolkit”、②实证文章写作常用到的50篇名家经验帖, 学者必读系列、③过去10年AER上关于中国主题的Articles专辑、④AEA公布2017-19年度最受关注的十大研究话题, 给你的选题方向,受到各位学者欢迎和热议,很多博士生导师纷纷推荐给指导的学生参阅。
之前,咱们小组引荐了1.Python中的计量回归模块及所有模块概览,2.空间计量软件代码资源集锦(Matlab/R/Python/SAS/Stata), 不再因空间效应而感到孤独,3.回归、分类与聚类:三大方向剖解机器学习算法的优缺点(附Python和R实现),4.机器学习第一书, 数据挖掘, 推理和预测,5.从线性回归到机器学习, 一张图帮你文献综述,6.11种与机器学习相关的多元变量分析方法汇总,7.机器学习和大数据计量经济学, 你必须阅读一下这篇,8.机器学习与Econometrics的书籍推荐, 值得拥有的经典,9.机器学习在微观计量的应用最新趋势: 大数据和因果推断,10.机器学习在微观计量的应用最新趋势: 回归模型,11.机器学习对计量经济学的影响, AEA年会独家报道,12.机器学习,可异于数理统计等,受到很多年轻学者的推崇和积极评价。
1.与Stata的比较
对于来自 Stata 的潜在用户,本节旨在演示如何在 pandas 中做各种类似Stata的操作。
如果您是 pandas 的新手,您可能需要先阅读十分钟入门Pandas 以熟悉本库。
按照惯例,我们按如下方式导入 pandas 和 NumPy:
In [1]: import pandas as pd
In [2]: import numpy as np
注意
在本教程中,DataFrame
将通过调用显示 pandas df.head()
,它将显示该行的前N行(默认为5行)DataFrame
。这通常用于交互式工作(例如Jupyter笔记本或终端) - Stata中的等价物将是:
list in 1/5
数据结构
一般术语对照表
Pandas | Stata |
---|---|
DataFrame | 数据集(data set) |
column | 变量(variable) |
row | 观察(observation) |
groupby | bysort |
NaN | . |
DataFrame
/ Series
pandas 中的 DataFrame
类似于 Stata
数据集-具有不同类型的标记列的二维数据源。如本文档所示,几乎任何可以应用于Stata中的数据集的操作也可以在 pandas 中完成。
Series
是表示DataFrame的一列的数据结构。Stata 对于单个列没有单独的数据结构,但是通常,使用 Series
类似于引用Stata中的数据集的列。
Index
每个 DataFrame
和 Series
在数据 行 上都有一个叫 Index
-label 的标签。在 Stata 中没有相似的概念。在Stata中,数据集的行基本上是无标签的,除了可以用 _n
访问的隐式整数索引。
在pandas中,如果未指定索引,则默认情况下也使用整数索引(第一行= 0,第二行= 1,依此类推)。虽然使用标记Index
或 MultiIndex
可以启用复杂的分析,并且最终是 pandas 理解的重要部分,但是对于这种比较,我们基本上会忽略它, Index
并且只是将其DataFrame
视为列的集合。有关如何有效使用的更多信息, 请参阅索引文档Index
。
数据输入/输出
从价值观构建数据帧
通过将数据放在input
语句之后并指定列名,可以从指定值构建Stata数据集。
input x y
1 2
3 4
5 6
end
pandas 的 DataFrame
可以用许多不同的方式构建,但对于少量的值,通常可以方便地将其指定为Python字典,其中键是列名,值是数据。
In [3]: df = pd.DataFrame({'x': [1, 3, 5], 'y': [2, 4, 6]})
In [4]: df
Out[4]:
x y
0 1 2
1 3 4
2 5 6
读取外部数据
与Stata一样,pandas提供了从多种格式读取数据的实用程序。tips
在pandas测试(csv)中找到的数据集将用于以下许多示例中。
Stata提供将csv数据读入内存中的数据集。如果文件在当前工作目录中,我们可以按如下方式导入它。import delimited````tips.csv
import delimited tips.csv
pandas 方法是read_csv()
类似的。此外,如果提供了网址,它将自动下载数据集。
In [5]: url = ('https://raw.github.com/pandas-dev'
...: '/pandas/master/pandas/tests/data/tips.csv')
...:
In [6]: tips = pd.read_csv(url)
In [7]: tips.head()
Out[7]:
total_bill tip sex smoker day time size
0 16.99 1.01 Female No Sun Dinner 2
1 10.34 1.66 Male No Sun Dinner 3
2 21.01 3.50 Male No Sun Dinner 3
3 23.68 3.31 Male No Sun Dinner 2
4 24.59 3.61 Female No Sun Dinner 4
比如,可以使用许多参数来指定数据应该如何解析。例如,如果数据是由制表符分隔的,没有列名,并且存在于当前工作目录中,则pandas命令将为:import delimited
read_csv()
tips = pd.read_csv('tips.csv', sep='\t', header=None)
# alternatively, read_table is an alias to read_csv with tab delimiter
tips = pd.read_table('tips.csv', header=None)
pandas 还可以用于 .dta
的文件格式中。使用read_stata()
函数读取格式的Stata数据集。
df = pd.read_stata('data.dta')
除了text / csv和Stata文件之外,pandas还支持各种其他数据格式,如Excel,SAS,HDF5,Parquet和SQL数据库。这些都是通过pd.read_*
函数读取的。有关更多详细信息,请参阅IO文档。
导出数据
stata 中 import delimated
的反向操作是 export delimated
。
export delimited tips2.csv
类似地,在 pandas 中,read_csv
的反向操作是DataFrame.to_csv()
。
tips.to_csv('tips2.csv')
pandas 还可以使用DataFrame.to_stata()
方法导出为Stata文件格式。
tips.to_stata('tips2.dta')
数据操作
列上的操作
在Stata中,任意数学表达式可以与新列或现有列上的generate
和 replace
命令一起使用。该drop
命令从数据集中删除列。
replace total_bill = total_bill - 2
generate new_bill = total_bill / 2
drop new_bill
pandas 通过指定个体提供了类似的矢量化操作Series
中DataFrame
。可以以相同的方式分配新列。该DataFrame.drop()
方法从中删除一列DataFrame
。
In [8]: tips['total_bill'] = tips['total_bill'] - 2
In [9]: tips['new_bill'] = tips['total_bill'] / 2
In [10]: tips.head()
Out[10]:
total_bill tip sex smoker day time size new_bill
0 14.99 1.01 Female No Sun Dinner 2 7.495
1 8.34 1.66 Male No Sun Dinner 3 4.170
2 19.01 3.50 Male No Sun Dinner 3 9.505
3 21.68 3.31 Male No Sun Dinner 2 10.840
4 22.59 3.61 Female No Sun Dinner 4 11.295
In [11]: tips = tips.drop('new_bill', axis=1)
过滤
在Stata中过滤是通过 if
一个或多个列上的子句完成的。
list if total_bill > 10
DataFrame可以通过多种方式进行过滤; 最直观的是使用 布尔索引。
In [12]: tips[tips['total_bill'] > 10].head()
Out[12]:
total_bill tip sex smoker day time size
0 14.99 1.01 Female No Sun Dinner 2
2 19.01 3.50 Male No Sun Dinner 3
3 21.68 3.31 Male No Sun Dinner 2
4 22.59 3.61 Female No Sun Dinner 4
5 23.29 4.71 Male No Sun Dinner 4
如果/那么逻辑
在Stata中,if
子句也可用于创建新列。
generate bucket = "low" if total_bill < 10
replace bucket = "high" if total_bill >= 10
使用 numpy
的 where
方法可以在 pandas 中完成相同的操作。
In [13]: tips['bucket'] = np.where(tips['total_bill'] < 10, 'low', 'high')
In [14]: tips.head()
Out[14]:
total_bill tip sex smoker day time size bucket
0 14.99 1.01 Female No Sun Dinner 2 high
1 8.34 1.66 Male No Sun Dinner 3 low
2 19.01 3.50 Male No Sun Dinner 3 high
3 21.68 3.31 Male No Sun Dinner 2 high
4 22.59 3.61 Female No Sun Dinner 4 high
日期功能
Stata提供了各种函数来对date / datetime列进行操作。
generate date1 = mdy(1, 15, 2013)
generate date2 = date("Feb152015", "MDY")
generate date1_year = year(date1)
generate date2_month = month(date2)
* shift date to beginning of next month
generate date1_next = mdy(month(date1) + 1, 1, year(date1)) if month(date1) != 12
replace date1_next = mdy(1, 1, year(date1) + 1) if month(date1) == 12
generate months_between = mofd(date2) - mofd(date1)
list date1 date2 date1_year date2_month date1_next months_between
等效的 pandas 操作如下所示。除了这些功能外,pandas 还支持 Stata 中不具备的其他时间序列功能(例如时区处理和自定义偏移) - 有关详细信息,请参阅时间序列文档。
In [15]: tips['date1'] = pd.Timestamp('2013-01-15')
In [16]: tips['date2'] = pd.Timestamp('2015-02-15')
In [17]: tips['date1_year'] = tips['date1'].dt.year
In [18]: tips['date2_month'] = tips['date2'].dt.month
In [19]: tips['date1_next'] = tips['date1'] + pd.offsets.MonthBegin()
In [20]: tips['months_between'] = (tips['date2'].dt.to_period('M')
....: - tips['date1'].dt.to_period('M'))
....:
In [21]: tips[['date1', 'date2', 'date1_year', 'date2_month', 'date1_next',
....: 'months_between']].head()
....:
Out[21]:
date1 date2 date1_year date2_month date1_next months_between
0 2013-01-15 2015-02-15 2013 2 2013-02-01 <25 * MonthEnds>
1 2013-01-15 2015-02-15 2013 2 2013-02-01 <25 * MonthEnds>
2 2013-01-15 2015-02-15 2013 2 2013-02-01 <25 * MonthEnds>
3 2013-01-15 2015-02-15 2013 2 2013-02-01 <25 * MonthEnds>
4 2013-01-15 2015-02-15 2013 2 2013-02-01 <25 * MonthEnds>
列的选择
Stata 提供了选择,删除和重命名列的关键字。
keep sex total_bill tip
drop sex
rename total_bill total_bill_2
下面的 pandas 表示相同的操作。请注意,与 Stata 相比,这些操作不会发生。要使这些更改保持不变,请将操作分配回变量。
# keep
In [22]: tips[['sex', 'total_bill', 'tip']].head()
Out[22]:
sex total_bill tip
0 Female 14.99 1.01
1 Male 8.34 1.66
2 Male 19.01 3.50
3 Male 21.68 3.31
4 Female 22.59 3.61
# drop
In [23]: tips.drop('sex', axis=1).head()
Out[23]:
total_bill tip smoker day time size
0 14.99 1.01 No Sun Dinner 2
1 8.34 1.66 No Sun Dinner 3
2 19.01 3.50 No Sun Dinner 3
3 21.68 3.31 No Sun Dinner 2
4 22.59 3.61 No Sun Dinner 4
# rename
In [24]: tips.rename(columns={'total_bill': 'total_bill_2'}).head()
Out[24]:
total_bill_2 tip sex smoker day time size
0 14.99 1.01 Female No Sun Dinner 2
1 8.34 1.66 Male No Sun Dinner 3
2 19.01 3.50 Male No Sun Dinner 3
3 21.68 3.31 Male No Sun Dinner 2
4 22.59 3.61 Female No Sun Dinner 4
按值排序
Stata中的排序是通过 sort
sort sex total_bill
pandas 对象有一个DataFrame.sort_values()
方法,它采用列表进行排序。
In [25]: tips = tips.sort_values(['sex', 'total_bill'])
In [26]: tips.head()
Out[26]:
total_bill tip sex smoker day time size
67 1.07 1.00 Female Yes Sat Dinner 1
92 3.75 1.00 Female Yes Fri Dinner 2
111 5.25 1.00 Female No Sat Dinner 1
145 6.35 1.50 Female No Thur Lunch 2
135 6.51 1.25 Female No Thur Lunch 2
字符串处理
查找字符串的长度
Stata 分别使用ASCII和Unicode字符串 strlen()
和 ustrlen()
函数确定字符串的长度。
generate strlen_time = strlen(time)
generate ustrlen_time = ustrlen(time)
Python 使用该 len
函数确定字符串的长度。在Python 3中,所有字符串都是Unicode字符串。len
包括尾随空白。使用len
和rstrip
排除尾随空格。
In [27]: tips['time'].str.len().head()
Out[27]:
67 6
92 6
111 6
145 5
135 5
Name: time, dtype: int64
In [28]: tips['time'].str.rstrip().str.len().head()
Out[28]:
67 6
92 6
111 6
145 5
135 5
Name: time, dtype: int64
找到字符串的位置
Stata使用该strpos()
函数确定字符串中字符的位置。这将获取第一个参数定义的字符串,并搜索您提供的子字符串的第一个位置作为第二个参数。
generate str_position = strpos(sex, "ale")
Python使用find()
函数确定字符串中字符的位置。find
搜索子字符串的第一个位置。如果找到子字符串,则该函数返回其位置。请记住,Python索引是从零开始的,如果找不到子串,函数将返回-1。
In [29]: tips['sex'].str.find("ale").head()
Out[29]:
67 3
92 3
111 3
145 3
135 3
Name: sex, dtype: int64
按位置提取字符串
Stata根据substr()
函数的位置从字符串中提取字符串。
generate short_sex = substr(sex, 1, 1)
使用pandas,您可以使用[]
符号从位置位置提取字符串中的子字符串。请记住,Python索引是从零开始的。
In [30]: tips['sex'].str[0:1].head()
Out[30]:
67 F
92 F
111 F
145 F
135 F
Name: sex, dtype: object
提取第n个字符
Stata word()
函数返回字符串中的第n个单词。第一个参数是要解析的字符串,第二个参数指定要提取的字。
clear
input str20 string
"John Smith"
"Jane Cook"
end
generate first_name = word(name, 1)
generate last_name = word(name, -1)
Python使用正则表达式根据文本从字符串中提取字符串。有更强大的方法,但这只是一个简单的方法。
In [31]: firstlast = pd.DataFrame({'string': ['John Smith', 'Jane Cook']})
In [32]: firstlast['First_Name'] = firstlast['string'].str.split(" ", expand=True)[0]
In [33]: firstlast['Last_Name'] = firstlast['string'].str.rsplit(" ", expand=True)[0]
In [34]: firstlast
Out[34]:
string First_Name Last_Name
0 John Smith John John
1 Jane Cook Jane Jane
改变案例
所述的Stata strupper()
,strlower()
,strproper()
, ustrupper()
,ustrlower()
,和ustrtitle()
功能分别改变ASCII和Unicode字符串的情况下,。
clear
input str20 string
"John Smith"
"Jane Cook"
end
generate upper = strupper(string)
generate lower = strlower(string)
generate title = strproper(string)
list
等效Python的功能upper
,lower
和title
。
In [35]: firstlast = pd.DataFrame({'string': ['John Smith', 'Jane Cook']})
In [36]: firstlast['upper'] = firstlast['string'].str.upper()
In [37]: firstlast['lower'] = firstlast['string'].str.lower()
In [38]: firstlast['title'] = firstlast['string'].str.title()
In [39]: firstlast
Out[39]:
string upper lower title
0 John Smith JOHN SMITH john smith John Smith
1 Jane Cook JANE COOK jane cook Jane Cook
合并
合并示例中将使用以下表格
In [40]: df1 = pd.DataFrame({'key': ['A', 'B', 'C', 'D'],
....: 'value': np.random.randn(4)})
....:
In [41]: df1
Out[41]:
key value
0 A 0.469112
1 B -0.282863
2 C -1.509059
3 D -1.135632
In [42]: df2 = pd.DataFrame({'key': ['B', 'D', 'D', 'E'],
....: 'value': np.random.randn(4)})
....:
In [43]: df2
Out[43]:
key value
0 B 1.212112
1 D -0.173215
2 D 0.119209
3 E -1.044236
在Stata中,要执行合并,一个数据集必须在内存中,另一个必须作为磁盘上的文件名引用。相比之下,Python必须DataFrames
已经在内存中。
默认情况下,Stata执行外部联接,其中两个数据集的所有观察值在合并后都保留在内存中。通过使用在_merge
变量中创建的值,可以仅保留来自初始数据集,合并数据集或两者的交集的观察 。
* First create df2 and save to disk
clear
input str1 key
B
D
D
E
end
generate value = rnormal()
save df2.dta
* Now create df1 in memory
clear
input str1 key
A
B
C
D
end
generate value = rnormal()
preserve
* Left join
merge 1:n key using df2.dta
keep if _merge == 1
* Right join
restore, preserve
merge 1:n key using df2.dta
keep if _merge == 2
* Inner join
restore, preserve
merge 1:n key using df2.dta
keep if _merge == 3
* Outer join
restore
merge 1:n key using df2.dta
pandas 的 DataFrames 有一个DataFrame.merge()
提供类似功能的方法。请注意,通过how
关键字可以实现不同的连接类型。
In [44]: inner_join = df1.merge(df2, on=['key'], how='inner')
In [45]: inner_join
Out[45]:
key value_x value_y
0 B -0.282863 1.212112
1 D -1.135632 -0.173215
2 D -1.135632 0.119209
In [46]: left_join = df1.merge(df2, on=['key'], how='left')
In [47]: left_join
Out[47]:
key value_x value_y
0 A 0.469112 NaN
1 B -0.282863 1.212112
2 C -1.509059 NaN
3 D -1.135632 -0.173215
4 D -1.135632 0.119209
In [48]: right_join = df1.merge(df2, on=['key'], how='right')
In [49]: right_join
Out[49]:
key value_x value_y
0 B -0.282863 1.212112
1 D -1.135632 -0.173215
2 D -1.135632 0.119209
3 E NaN -1.044236
In [50]: outer_join = df1.merge(df2, on=['key'], how='outer')
In [51]: outer_join
Out[51]:
key value_x value_y
0 A 0.469112 NaN
1 B -0.282863 1.212112
2 C -1.509059 NaN
3 D -1.135632 -0.173215
4 D -1.135632 0.119209
5 E NaN -1.044236
缺少数据
像Stata一样,pandas 有缺失数据的表示 - 特殊浮点值NaN
(不是数字)。许多语义都是一样的; 例如,丢失的数据通过数字操作传播,默认情况下会被聚合忽略。
In [52]: outer_join
Out[52]:
key value_x value_y
0 A 0.469112 NaN
1 B -0.282863 1.212112
2 C -1.509059 NaN
3 D -1.135632 -0.173215
4 D -1.135632 0.119209
5 E NaN -1.044236
In [53]: outer_join['value_x'] + outer_join['value_y']
Out[53]:
0 NaN
1 0.929249
2 NaN
3 -1.308847
4 -1.016424
5 NaN
dtype: float64
In [54]: outer_join['value_x'].sum()
Out[54]: -3.5940742896293765
一个区别是丢失的数据无法与其哨兵值进行比较。例如,在 Stata 中,您可以执行此操作以过滤缺失值。
* Keep missing values
list if value_x == .
* Keep non-missing values
list if value_x != .
这在 pandas 中不起作用。相反,应使用pd.isna()
或pd.notna()
函数进行比较。
In [55]: outer_join[pd.isna(outer_join['value_x'])]
Out[55]:
key value_x value_y
5 E NaN -1.044236
In [56]: outer_join[pd.notna(outer_join['value_x'])]
Out[56]:
key value_x value_y
0 A 0.469112 NaN
1 B -0.282863 1.212112
2 C -1.509059 NaN
3 D -1.135632 -0.173215
4 D -1.135632 0.119209
pandas 还提供了多种处理丢失数据的方法,其中一些方法在Stata中表达起来很有挑战性。例如,有一些方法可以删除具有任何缺失值的所有行,用指定值(如平均值)替换缺失值,或从前一行向前填充。有关详细信息,请参阅缺失数据文档。
# Drop rows with any missing value
In [57]: outer_join.dropna()
Out[57]:
key value_x value_y
1 B -0.282863 1.212112
3 D -1.135632 -0.173215
4 D -1.135632 0.119209
# Fill forwards
In [58]: outer_join.fillna(method='ffill')
Out[58]:
key value_x value_y
0 A 0.469112 NaN
1 B -0.282863 1.212112
2 C -1.509059 1.212112
3 D -1.135632 -0.173215
4 D -1.135632 0.119209
5 E -1.135632 -1.044236
# Impute missing values with the mean
In [59]: outer_join['value_x'].fillna(outer_join['value_x'].mean())
Out[59]:
0 0.469112
1 -0.282863
2 -1.509059
3 -1.135632
4 -1.135632
5 -0.718815
Name: value_x, dtype: float64
的GroupBy
聚合
Stata collapse
可用于按一个或多个关键变量进行分组,并计算数字列上的聚合。
collapse (sum) total_bill tip, by(sex smoker)
pandas提供了一种groupby
允许类似聚合的灵活机制。有关 更多详细信息和示例,请参阅groupby文档。
In [60]: tips_summed = tips.groupby(['sex', 'smoker'])['total_bill', 'tip'].sum()
In [61]: tips_summed.head()
Out[61]:
total_bill tip
sex smoker
Female No 869.68 149.77
Yes 527.27 96.74
Male No 1725.75 302.00
Yes 1217.07 183.07
转换
在Stata中,如果组聚合需要与原始数据集一起使用bysort
,通常会使用egen()
。例如,减去吸烟者组每次观察的平均值。
bysort sex smoker: egen group_bill = mean(total_bill)
generate adj_total_bill = total_bill - group_bill
pandas groupby
提供了一种transform
机制,允许在一个操作中简洁地表达这些类型的操作。
In [62]: gb = tips.groupby('smoker')['total_bill']
In [63]: tips['adj_total_bill'] = tips['total_bill'] - gb.transform('mean')
In [64]: tips.head()
Out[64]:
total_bill tip sex smoker day time size adj_total_bill
67 1.07 1.00 Female Yes Sat Dinner 1 -17.686344
92 3.75 1.00 Female Yes Fri Dinner 2 -15.006344
111 5.25 1.00 Female No Sat Dinner 1 -11.938278
145 6.35 1.50 Female No Thur Lunch 2 -10.838278
135 6.51 1.25 Female No Thur Lunch 2 -10.678278
按组处理
除聚合外,pandas groupby
还可用于复制bysort
Stata中的大多数其他处理。例如,以下示例按性别/吸烟者组列出当前排序顺序中的第一个观察结果。
bysort sex smoker: list if _n == 1
在 pandas 中,这将写成:
In [65]: tips.groupby(['sex', 'smoker']).first()
Out[65]:
total_bill tip day time size adj_total_bill
sex smoker
Female No 5.25 1.00 Sat Dinner 1 -11.938278
Yes 1.07 1.00 Sat Dinner 1 -17.686344
Male No 5.51 2.00 Thur Lunch 2 -11.678278
Yes 5.25 5.15 Sun Dinner 2 -13.506344
其他注意事项
磁盘与内存
pandas 和 Stata 都只在内存中运行。这意味着能够在 pandas 中加载的数据大小受机器内存的限制。如果需要进行核心处理,则有一种可能性是dask.dataframe 库,它为磁盘上的pandas功能提供了一个子集DataFrame
。
2.与R/R库的比较
由于 pandas
旨在为人们提供可以替代R的大量数据操作和分析的功能,因此本章节会提供较为详细的R语言的介绍以及与相关的许多第三方库的对比说明,比如我们的 pandas
库。在与R和CRAN库的比较中,我们关注以下事项:
功能/灵活性:每个工具可以/不可以做什么
性能:操作速度有多快。硬性数字/基准是优选的
易于使用:一种工具更容易/更难使用(您可能需要对此进行判断,并进行并排代码比较)
此页面还为这些R包的用户提供了一些翻译指南。
要将 DataFrame
对象从 pandas
转化为到 R 的数据类型,有一个选择是采用HDF5文件,请参阅外部兼容性示例。
快速参考
我们将从快速参考指南开始,将dplyr与pandas等效的一些常见R操作配对。
查询、过滤、采样
R | Pandas |
---|---|
dim(df) | df.shape |
head(df) | df.head() |
slice(df, 1:10) | df.iloc[:9] |
filter(df, col1 == 1, col2 == 1) | df.query('col1 == 1 & col2 == 1') |
df[df$col1 == 1 & df$col2 == 1,] | df[(df.col1 == 1) & (df.col2 == 1)] |
select(df, col1, col2) | df[['col1', 'col2']] |
select(df, col1:col3) | df.loc[:, 'col1':'col3'] |
select(df, -(col1:col3)) | df.drop(cols_to_drop, axis=1)但是看[1] |
distinct(select(df, col1)) | df[['col1']].drop_duplicates() |
distinct(select(df, col1, col2)) | df[['col1', 'col2']].drop_duplicates() |
sample_n(df, 10) | df.sample(n=10) |
sample_frac(df, 0.01) | df.sample(frac=0.01) |
Note
R表示列的子集 (select(df,col1:col3)
的缩写更接近 Pandas 的写法,如果您有列的列表,例如 df[cols[1:3]
或 df.drop(cols[1:3])
,按列名执行此操作可能会引起混乱。
排序
R | Pandas |
---|---|
arrange(df, col1, col2) | df.sort_values(['col1', 'col2']) |
arrange(df, desc(col1)) | df.sort_values('col1', ascending=False) |
变换
R | Pandas |
---|---|
select(df, col_one = col1) | df.rename(columns={'col1': 'col_one'})['col_one'] |
rename(df, col_one = col1) | df.rename(columns={'col1': 'col_one'}) |
mutate(df, c=a-b) | df.assign(c=df.a-df.b) |
分组和组合
R | Pandas |
---|---|
summary(df) | df.describe() |
gdf <- group_by(df, col1) | gdf = df.groupby('col1') |
summarise(gdf, avg=mean(col1, na.rm=TRUE)) | df.groupby('col1').agg({'col1': 'mean'}) |
summarise(gdf, total=sum(col1)) | df.groupby('col1').sum() |
基本的R用法
用Rc
方法来进行切片操作
R使您可以轻松地按名称访问列(data.frame
)
df <- data.frame(a=rnorm(5), b=rnorm(5), c=rnorm(5), d=rnorm(5), e=rnorm(5))
df[, c("a", "c", "e")]
或整数位置
df <- data.frame(matrix(rnorm(1000), ncol=100))
df[, c(1:10, 25:30, 40, 50:100)]
按名称选择多个pandas
的列非常简单
In [1]: df = pd.DataFrame(np.random.randn(10, 3), columns=list('abc'))
In [2]: df[['a', 'c']]
Out[2]:
a c
0 0.469112 -1.509059
1 -1.135632 -0.173215
2 0.119209 -0.861849
3 -2.104569 1.071804
4 0.721555 -1.039575
5 0.271860 0.567020
6 0.276232 -0.673690
7 0.113648 0.524988
8 0.404705 -1.715002
9 -1.039268 -1.157892
In [3]: df.loc[:, ['a', 'c']]
Out[3]:
a c
0 0.469112 -1.509059
1 -1.135632 -0.173215
2 0.119209 -0.861849
3 -2.104569 1.071804
4 0.721555 -1.039575
5 0.271860 0.567020
6 0.276232 -0.673690
7 0.113648 0.524988
8 0.404705 -1.715002
9 -1.039268 -1.157892
通过整数位置选择多个不连续的列可以通过iloc
索引器属性和 numpy.r_
的组合来实现。
In [4]: named = list('abcdefg')
In [5]: n = 30
In [6]: columns = named + np.arange(len(named), n).tolist()
In [7]: df = pd.DataFrame(np.random.randn(n, n), columns=columns)
In [8]: df.iloc[:, np.r_[:10, 24:30]]
Out[8]:
a b c d e f g 7 8 9 24 25 26 27 28 29
0 -1.344312 0.844885 1.075770 -0.109050 1.643563 -1.469388 0.357021 -0.674600 -1.776904 -0.968914 -1.170299 -0.226169 0.410835 0.813850 0.132003 -0.827317
1 -0.076467 -1.187678 1.130127 -1.436737 -1.413681 1.607920 1.024180 0.569605 0.875906 -2.211372 0.959726 -1.110336 -0.619976 0.149748 -0.732339 0.687738
2 0.176444 0.403310 -0.154951 0.301624 -2.179861 -1.369849 -0.954208 1.462696 -1.743161 -0.826591 0.084844 0.432390 1.519970 -0.493662 0.600178 0.274230
3 0.132885 -0.023688 2.410179 1.450520 0.206053 -0.251905 -2.213588 1.063327 1.266143 0.299368 -2.484478 -0.281461 0.030711 0.109121 1.126203 -0.977349
4 1.474071 -0.064034 -1.282782 0.781836 -1.071357 0.441153 2.353925 0.583787 0.221471 -0.744471 -1.197071 -1.066969 -0.303421 -0.858447 0.306996 -0.028665
.. ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
25 1.492125 -0.068190 0.681456 1.221829 -0.434352 1.204815 -0.195612 1.251683 -1.040389 -0.796211 1.944517 0.042344 -0.307904 0.428572 0.880609 0.487645
26 0.725238 0.624607 -0.141185 -0.143948 -0.328162 2.095086 -0.608888 -0.926422 1.872601 -2.513465 -0.846188 1.190624 0.778507 1.008500 1.424017 0.717110
27 1.262419 1.950057 0.301038 -0.933858 0.814946 0.181439 -0.110015 -2.364638 -1.584814 0.307941 -1.341814 0.334281 -0.162227 1.007824 2.826008 1.458383
28 -1.585746 -0.899734 0.921494 -0.211762 -0.059182 0.058308 0.915377 -0.696321 0.150664 -3.060395 0.403620 -0.026602 -0.240481 0.577223 -1.088417 0.326687
29 -0.986248 0.169729 -1.158091 1.019673 0.646039 0.917399 -0.010435 0.366366 0.922729 0.869610 -1.209247 -0.671466 0.332872 -2.013086 -1.602549 0.333109
[30 rows x 16 columns]
aggregate
在R中,您可能希望将数据分成几个子集,并计算每个子集的平均值。使用名为df
的data.frame并将其分成组by1
和by2
:
df <- data.frame(
v1 = c(1,3,5,7,8,3,5,NA,4,5,7,9),
v2 = c(11,33,55,77,88,33,55,NA,44,55,77,99),
by1 = c("red", "blue", 1, 2, NA, "big", 1, 2, "red", 1, NA, 12),
by2 = c("wet", "dry", 99, 95, NA, "damp", 95, 99, "red", 99, NA, NA))
aggregate(x=df[, c("v1", "v2")], by=list(mydf2$by1, mydf2$by2), FUN = mean)
该groupby()
方法类似于基本R的 aggregate
函数。
In [9]: df = pd.DataFrame(
...: {'v1': [1, 3, 5, 7, 8, 3, 5, np.nan, 4, 5, 7, 9],
...: 'v2': [11, 33, 55, 77, 88, 33, 55, np.nan, 44, 55, 77, 99],
...: 'by1': ["red", "blue", 1, 2, np.nan, "big", 1, 2, "red", 1, np.nan, 12],
...: 'by2': ["wet", "dry", 99, 95, np.nan, "damp", 95, 99, "red", 99, np.nan,
...: np.nan]})
...:
In [10]: g = df.groupby(['by1', 'by2'])
In [11]: g[['v1', 'v2']].mean()
Out[11]:
v1 v2
by1 by2
1 95 5.0 55.0
99 5.0 55.0
2 95 7.0 77.0
99 NaN NaN
big damp 3.0 33.0
blue dry 3.0 33.0
red red 4.0 44.0
wet 1.0 11.0
有关更多详细信息和示例,请参阅groupby文档。
match
/ %in%
在R中选择数据的常用方法是使用%in%
使用该函数定义的数据match
。运算符%in%
用于返回指示是否存在匹配的逻辑向量:
s <- 0:4
s %in% c(2,4)
该isin()
方法类似于R %in%
运算符:
In [12]: s = pd.Series(np.arange(5), dtype=np.float32)
In [13]: s.isin([2, 4])
Out[13]:
0 False
1 False
2 True
3 False
4 True
dtype: bool
该match
函数返回其第二个参数匹配位置的向量:
s <- 0:4
match(s, c(2,4))
有关更多详细信息和示例,请参阅重塑文档。
tapply
tapply
类似于aggregate
,但数据可以是一个参差不齐的数组,因为子类大小可能是不规则的。使用调用的data.frame baseball
,并根据数组检索信息team
:
baseball <-
data.frame(team = gl(5, 5,
labels = paste("Team", LETTERS[1:5])),
player = sample(letters, 25),
batting.average = runif(25, .200, .400))
tapply(baseball$batting.average, baseball.example$team,
max)
在pandas
我们可以使用pivot_table()
方法来处理这个:
In [14]: import random
In [15]: import string
In [16]: baseball = pd.DataFrame(
....: {'team': ["team %d" % (x + 1) for x in range(5)] * 5,
....: 'player': random.sample(list(string.ascii_lowercase), 25),
....: 'batting avg': np.random.uniform(.200, .400, 25)})
....:
In [17]: baseball.pivot_table(values='batting avg', columns='team', aggfunc=np.max)
Out[17]:
team team 1 team 2 team 3 team 4 team 5
batting avg 0.352134 0.295327 0.397191 0.394457 0.396194
有关更多详细信息和示例,请参阅重塑文档。
subset
该query()
方法类似于基本R subset
函数。在R中,您可能希望获取data.frame
一列的值小于另一列的值的行:
df <- data.frame(a=rnorm(10), b=rnorm(10))
subset(df, a <= b)
df[df$a <= df$b,] # note the comma
在pandas
,有几种方法可以执行子集化。您可以使用 query()
或传递表达式,就像它是索引/切片以及标准布尔索引一样:
In [18]: df = pd.DataFrame({'a': np.random.randn(10), 'b': np.random.randn(10)})
In [19]: df.query('a <= b')
Out[19]:
a b
1 0.174950 0.552887
2 -0.023167 0.148084
3 -0.495291 -0.300218
4 -0.860736 0.197378
5 -1.134146 1.720780
7 -0.290098 0.083515
8 0.238636 0.946550
In [20]: df[df.a <= df.b]
Out[20]:
a b
1 0.174950 0.552887
2 -0.023167 0.148084
3 -0.495291 -0.300218
4 -0.860736 0.197378
5 -1.134146 1.720780
7 -0.290098 0.083515
8 0.238636 0.946550
In [21]: df.loc[df.a <= df.b]
Out[21]:
a b
1 0.174950 0.552887
2 -0.023167 0.148084
3 -0.495291 -0.300218
4 -0.860736 0.197378
5 -1.134146 1.720780
7 -0.290098 0.083515
8 0.238636 0.946550
有关更多详细信息和示例,请参阅查询文档。
with
使用df
带有列的R中调用的data.frame的表达式a
, b
将使用with
如下方式进行求值:
df <- data.frame(a=rnorm(10), b=rnorm(10))
with(df, a + b)
df$a + df$b # same as the previous expression
在pandas
等效表达式中,使用该 eval()
方法将是:
In [22]: df = pd.DataFrame({'a': np.random.randn(10), 'b': np.random.randn(10)})
In [23]: df.eval('a + b')
Out[23]:
0 -0.091430
1 -2.483890
2 -0.252728
3 -0.626444
4 -0.261740
5 2.149503
6 -0.332214
7 0.799331
8 -2.377245
9 2.104677
dtype: float64
In [24]: df.a + df.b # same as the previous expression
Out[24]:
0 -0.091430
1 -2.483890
2 -0.252728
3 -0.626444
4 -0.261740
5 2.149503
6 -0.332214
7 0.799331
8 -2.377245
9 2.104677
dtype: float64
在某些情况下,eval()
将比纯Python中的评估快得多。有关更多详细信息和示例,请参阅eval文档。
plyr
plyr
是用于数据分析的拆分应用组合策略的R库。这些函数围绕R,a
for arrays
,l
for lists
和d
for中的三个数据结构data.frame
。下表显示了如何在Python中映射这些数据结构。
R | Python |
---|---|
array | list |
lists | 字典(dist)或对象列表(list of objects) |
data.frame | dataframe |
ddply
在R中使用名为df
的data.frame的表达式,比如您有一个希望按月
汇总x
的需求:
require(plyr)
df <- data.frame(
x = runif(120, 1, 168),
y = runif(120, 7, 334),
z = runif(120, 1.7, 20.7),
month = rep(c(5,6,7,8),30),
week = sample(1:4, 120, TRUE)
)
ddply(df, .(month, week), summarize,
mean = round(mean(x), 2),
sd = round(sd(x), 2))
在pandas
等效表达式中,使用该 groupby()
方法将是:
In [25]: df = pd.DataFrame({'x': np.random.uniform(1., 168., 120),
....: 'y': np.random.uniform(7., 334., 120),
....: 'z': np.random.uniform(1.7, 20.7, 120),
....: 'month': [5, 6, 7, 8] * 30,
....: 'week': np.random.randint(1, 4, 120)})
....:
In [26]: grouped = df.groupby(['month', 'week'])
In [27]: grouped['x'].agg([np.mean, np.std])
Out[27]:
mean std
month week
5 1 63.653367 40.601965
2 78.126605 53.342400
3 92.091886 57.630110
6 1 81.747070 54.339218
2 70.971205 54.687287
3 100.968344 54.010081
7 1 61.576332 38.844274
2 61.733510 48.209013
3 71.688795 37.595638
8 1 62.741922 34.618153
2 91.774627 49.790202
3 73.936856 60.773900
有关更多详细信息和示例,请参阅groupby文档。
重塑/ reshape2
melt.array
使用a
在R中调用的3维数组的表达式,您希望将其融合到data.frame中:
a <- array(c(1:23, NA), c(2,3,4))
data.frame(melt(a))
在Python中,既然a
是一个列表,你可以简单地使用列表理解。
In [28]: a = np.array(list(range(1, 24)) + [np.NAN]).reshape(2, 3, 4)
In [29]: pd.DataFrame([tuple(list(x) + [val]) for x, val in np.ndenumerate(a)])
Out[29]:
0 1 2 3
0 0 0 0 1.0
1 0 0 1 2.0
2 0 0 2 3.0
3 0 0 3 4.0
4 0 1 0 5.0
.. .. .. .. ...
19 1 1 3 20.0
20 1 2 0 21.0
21 1 2 1 22.0
22 1 2 2 23.0
23 1 2 3 NaN
[24 rows x 4 columns]
melt.list
使用a
R中调用的列表的表达式,您希望将其融合到data.frame中:
a <- as.list(c(1:4, NA))
data.frame(melt(a))
在Python中,此列表将是元组列表,因此 DataFrame()
方法会根据需要将其转换为数据帧。
In [30]: a = list(enumerate(list(range(1, 5)) + [np.NAN]))
In [31]: pd.DataFrame(a)
Out[31]:
0 1
0 0 1.0
1 1 2.0
2 2 3.0
3 3 4.0
4 4 NaN
有关更多详细信息和示例,请参阅“进入数据结构”文档。
melt.data.frame
使用cheese
在R中调用的data.frame的表达式,您要在其中重新整形data.frame:
cheese <- data.frame(
first = c('John', 'Mary'),
last = c('Doe', 'Bo'),
height = c(5.5, 6.0),
weight = c(130, 150)
)
melt(cheese, id=c("first", "last"))
在Python中,该melt()
方法是R等价物:
In [32]: cheese = pd.DataFrame({'first': ['John', 'Mary'],
....: 'last': ['Doe', 'Bo'],
....: 'height': [5.5, 6.0],
....: 'weight': [130, 150]})
....:
In [33]: pd.melt(cheese, id_vars=['first', 'last'])
Out[33]:
first last variable value
0 John Doe height 5.5
1 Mary Bo height 6.0
2 John Doe weight 130.0
3 Mary Bo weight 150.0
In [34]: cheese.set_index(['first', 'last']).stack() # alternative way
Out[34]:
first last
John Doe height 5.5
weight 130.0
Mary Bo height 6.0
weight 150.0
dtype: float64
有关更多详细信息和示例,请参阅重塑文档。
cast
在R中acast
是一个表达式,它使用df
在R中调用的data.frame 来转换为更高维的数组:
df <- 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)
)
mdf <- melt(df, id=c("month", "week"))
acast(mdf, week ~ month ~ variable, mean)
在Python中,最好的方法是使用pivot_table()
:
In [35]: df = 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})
....:
In [36]: mdf = pd.melt(df, id_vars=['month', 'week'])
In [37]: pd.pivot_table(mdf, values='value', index=['variable', 'week'],
....: columns=['month'], aggfunc=np.mean)
....:
Out[37]:
month 5 6 7
variable week
x 1 93.888747 98.762034 55.219673
2 94.391427 38.112932 83.942781
y 1 94.306912 279.454811 227.840449
2 87.392662 193.028166 173.899260
z 1 11.016009 10.079307 16.170549
2 8.476111 17.638509 19.003494
类似地dcast
,使用df
R中调用的data.frame 来基于Animal
和聚合信息FeedType
:
df <- data.frame(
Animal = c('Animal1', 'Animal2', 'Animal3', 'Animal2', 'Animal1',
'Animal2', 'Animal3'),
FeedType = c('A', 'B', 'A', 'A', 'B', 'B', 'A'),
Amount = c(10, 7, 4, 2, 5, 6, 2)
)
dcast(df, Animal ~ FeedType, sum, fill=NaN)
# Alternative method using base R
with(df, tapply(Amount, list(Animal, FeedType), sum))
Python可以通过两种不同的方式处理它。首先,类似于上面使用pivot_table()
:
In [38]: df = pd.DataFrame({
....: 'Animal': ['Animal1', 'Animal2', 'Animal3', 'Animal2', 'Animal1',
....: 'Animal2', 'Animal3'],
....: 'FeedType': ['A', 'B', 'A', 'A', 'B', 'B', 'A'],
....: 'Amount': [10, 7, 4, 2, 5, 6, 2],
....: })
....:
In [39]: df.pivot_table(values='Amount', index='Animal', columns='FeedType',
....: aggfunc='sum')
....:
Out[39]:
FeedType A B
Animal
Animal1 10.0 5.0
Animal2 2.0 13.0
Animal3 6.0 NaN
第二种方法是使用该groupby()
方法:
In [40]: df.groupby(['Animal', 'FeedType'])['Amount'].sum()
Out[40]:
Animal FeedType
Animal1 A 10
B 5
Animal2 A 2
B 13
Animal3 A 6
Name: Amount, dtype: int64
有关更多详细信息和示例,请参阅重新整形文档或groupby文档。
factor
pandas具有分类数据的数据类型。
cut(c(1,2,3,4,5,6), 3)
factor(c(1,2,3,2,2,3))
在Pandas,这是完成与pd.cut
和astype("category")
:
In [41]: pd.cut(pd.Series([1, 2, 3, 4, 5, 6]), 3)
Out[41]:
0 (0.995, 2.667]
1 (0.995, 2.667]
2 (2.667, 4.333]
3 (2.667, 4.333]
4 (4.333, 6.0]
5 (4.333, 6.0]
dtype: category
Categories (3, interval[float64]): [(0.995, 2.667] < (2.667, 4.333] < (4.333, 6.0]]
In [42]: pd.Series([1, 2, 3, 2, 2, 3]).astype("category")
Out[42]:
0 1
1 2
2 3
3 2
4 2
5 3
dtype: category
Categories (3, int64): [1, 2, 3]
以上只显示与Stata, R软件的比较,以下二维码中包括“Python与Stata, R, SAS, SQL在数据处理上的比较全文”。
长按以上二维码阅读全文
对Python做计量估计感兴趣的学者,可以到社群或相关研究小组交流讨论。
拓展性阅读
1.用R语言做Econometrics的书籍推荐, 值得拥有的经典,2.18+1张图掌握R软件的方方面面, 还有谁, 还有谁?,3.用R语言做空间计量, 绝不容错过的简明教程,4.R软件中的时间序列分析程序包纵览,5.R软件画图指南针,摆脱丑图不是梦,6.平滑转移自回归模型(STAR)应用与在R软件的操作,7.用R语言做空间计量, 绝不容错过的简明教程,8.R语言函数最全总结, 机器学习从这里出发,9.R语言ggplot2的小抄, 绘图总结查阅,10.送|R语言全套视频和资料,异常珍贵的材料,11.2卷RDD断点回归使用手册, 含Stata和R软件操作流程
2年,计量经济圈公众号近1000篇文章,
Econometrics Circle
数据系列:空间矩阵 | 工企数据 | PM2.5 | 市场化指数 | CO2数据 | 夜间灯光 | 官员方言 | 微观数据 |
计量系列:匹配方法 | 内生性 | 工具变量 | DID | 面板数据 | 常用TOOL | 中介调节 | 时间序列 | RDD断点 | 合成控制 |
数据处理:Stata | R | Python | 缺失值 | CHIP/ CHNS/CHARLS/CFPS/CGSS等 |
干货系列:能源环境 | 效率研究 | 空间计量 | 国际经贸 | 计量软件 | 商科研究 | 机器学习 | SSCI | CSSCI | SSCI查询 |
计量经济圈组织了一个计量社群,有如下特征:热情互助最多、前沿趋势最多、社科资料最多、社科数据最多、科研牛人最多、海外名校最多。因此,建议积极进取和有强烈研习激情的中青年学者到社群交流探讨,始终坚信优秀是通过感染优秀而互相成就彼此的。