与Stata的比较#
对于可能来自 Stata 的用户,本页旨在演示如何在pandas中执行不同的Stata操作。
如果你是 pandas 新手,你可能想先阅读 10 Minutes to pandas 来熟悉该库。
按照惯例,我们像这样导入 pandas 和 NumPy:
数据结构#
通用术语翻译#
pandas |
Stata |
|---|---|
|
data set |
column |
variable |
row |
observation |
groupby |
bysort |
|
|
DataFrame#
pandas中的 DataFrame 类似于Stata数据集——一个二维数据源,具有不同类型的带标签的列。正如本文档所示,几乎所有可以在Stata数据集中应用的运算,在pandas中也都可以实现。
Series#
Series 是代表 DataFrame 中某一列的数据结构。Stata没有用于单列的独立数据结构,但通常来说,处理 Series 类似于引用Stata数据集中的一列。
Index#
每个 DataFrame 和 Series 都有一个 Index —— 数据*行*的标签。Stata没有完全对应的概念。在Stata中,数据集的行基本上是无标签的,除了可以通过 _n 访问的隐式整数索引。
在 pandas 中,如果没有指定索引,默认也会使用整数索引(第一行 = 0,第二行 = 1,依此类推)。虽然使用带标签的 Index 或 MultiIndex 可以实现复杂的分析,并且最终是理解 pandas 的重要组成部分,但在此比较中,我们将基本忽略 Index,仅将 DataFrame 视为列的集合。有关如何有效使用 Index 的更多信息,请参阅 indexing documentation 。
副本 vs. 原地操作#
大多数 pandas 操作会返回 Series/DataFrame 的副本。要使更改“生效”,您需要将其赋给一个新变量:
sorted_df = df.sort_values("col1")
或者覆盖原始变量:
df = df.sort_values("col1")
备注
您会看到一些方法提供了 inplace=True 或 copy=False 关键字参数:
df.replace(5, inplace=True)
目前正在积极讨论弃用和删除大多数方法的 inplace 和 copy``(例如,``dropna),只保留一小部分方法(包括 replace)。在 Copy-on-Write 的上下文中,这两个关键字将不再需要。该提案可以在 here 找到。
数据输入/输出#
从值构建 DataFrame#
可以通过在 input 语句后放置数据并指定列名来从给定值构建Stata数据集。
input x y
1 2
3 4
5 6
end
pandas DataFrame 可以通过多种方式构建,但对于少量值,通常将其指定为 Python 字典会很方便,其中键是列名,值是数据。
读取外部数据#
Like Stata, pandas provides utilities for reading in data from
many formats. The tips data set, found within the pandas
tests (csv)
will be used in many of the following examples.
Stata 提供 import delimited 来将 csv 数据读入内存中的数据集。如果 tips.csv 文件位于当前工作目录中,我们可以这样导入它。
import delimited tips.csv
pandas 的方法是 read_csv() ,其功能类似。此外,如果提供 url,它还会自动下载数据集。
与 import delimited 类似,read_csv() 可以接受许多参数来指定数据如何解析。例如,如果数据是制表符分隔的,没有列名,并且存在于当前工作目录中,pandas 命令将是:
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 还可以使用 read_stata() 函数读取 .dta 格式的 Stata 数据集。
df = pd.read_stata("data.dta")
除了文本/csv 和 Stata 文件外,pandas 还支持多种其他数据格式,如 Excel、SAS、HDF5、Parquet 和 SQL 数据库。这些都可以通过 pd.read_* 函数读取。有关更多详细信息,请参阅 IO documentation 。
限制输出#
默认情况下,pandas 会截断大型 DataFrame 的输出,只显示第一行和最后一行。这可以通过 changing the pandas options 或使用 DataFrame.head() 或 DataFrame.tail() 来覆盖。
Stata 中的对应命令是:
list in 1/5
导出数据#
Stata 中 import delimited 的逆操作是 export delimited。
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 中删除一列。
过滤#
Stata 中的筛选是通过在一个或多个列上使用 if 子句来完成的。
list if total_bill > 10
DataFrame 可以通过多种方式进行过滤;其中最直观的是使用 boolean indexing 。
上面的语句只是将一个包含 True/False 对象的 Series 传递给 DataFrame,返回所有 True 的行。
If/then 逻辑#
在 Stata 中,if 子句也可以用来创建新列。
generate bucket = "low" if total_bill < 10
replace bucket = "high" if total_bill >= 10
在 pandas 中,可以使用来自 numpy 的 where 方法完成相同的操作。
日期功能#
Stata 提供各种函数来对日期/日期时间列执行操作。
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 中没有的其他时间序列功能(例如时区处理和自定义偏移量)——有关更多详细信息,请参阅 timeseries documentation 。
选择列#
Stata 提供关键字来选择、删除和重命名列。
keep sex total_bill tip
drop sex
rename total_bill total_bill_2
下面在 pandas 中显示了相同的操作。
保留特定列#
删除列#
重命名列#
按值排序#
Stata 中的排序是通过 sort 完成的。
sort sex total_bill
pandas 有一个 DataFrame.sort_values() 方法,它接受一个要排序的列列表。
字符串处理#
查找字符串长度#
Stata 使用 strlen() 和 ustrlen() 函数分别确定 ASCII 和 Unicode 字符串的长度。
generate strlen_time = strlen(time)
generate ustrlen_time = ustrlen(time)
您可以使用 Series.str.len() 查找字符串的长度。在 Python 3 中,所有字符串都是 Unicode 字符串。len 包含尾随空格。使用 len 和 rstrip 来排除尾随空格。
查找子字符串位置#
Stata 使用 strpos() 函数确定字符在字符串中的位置。该函数接受第一个参数定义的字符串,并搜索您作为第二个参数提供的子字符串的第一个位置。
generate str_position = strpos(sex, "ale")
您可以使用 Series.str.find() 方法查找字符串列中字符的位置。find 搜索子字符串的第一个位置。如果找到子字符串,则返回其位置。如果未找到,则返回 -1。请记住,Python 索引是从零开始的。
按位置提取子字符串#
Stata 使用 substr() 函数根据位置从字符串中提取子字符串。
generate short_sex = substr(sex, 1, 1)
使用 pandas,您可以使用 [] 符号通过位置从字符串中提取子字符串。请记住,Python 索引是从零开始的。
提取第 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)
在 pandas 中提取单词的最简单方法是按空格分割字符串,然后按索引引用单词。请注意,如果您需要更强大的方法,还有其他方法。
更改大小写#
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
等效的 pandas 方法是 Series.str.upper() 、Series.str.lower() 和 Series.str.title() 。
合并#
以下表将用于合并示例:
在 Stata 中,要执行合并,一个数据集必须在内存中,另一个数据集必须引用为磁盘上的文件名。相比之下,Python 必须同时将两个 DataFrame 加载到内存中。
默认情况下,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 有一个 merge() 方法,它提供了类似的功能。数据不必提前排序,并且可以通过 how 关键字来实现不同的连接类型。
缺失数据#
pandas 和 Stata 都有缺失数据的表示。
pandas 用特殊的浮点值 ``NaN``(非数字)表示缺失数据。其中许多语义是相同的;例如,缺失数据会在数值运算中传播,并且默认情况下会被聚合忽略。
一个区别是缺失数据不能与其哨兵值进行比较。例如,在 Stata 中,您可以这样做来过滤缺失值。
* Keep missing values
list if value_x == .
* Keep non-missing values
list if value_x != .
在 pandas 中,可以使用 Series.isna() 和 Series.notna() 来过滤行。
pandas 提供了 a variety of methods to work with missing data 。以下是一些示例:
删除包含缺失值的行#
向前填充(使用前一行值)#
用指定值替换缺失值#
使用平均值:
GroupBy#
聚合#
Stata 的 collapse 可用于按一个或多个键变量进行分组,并对数值列进行聚合计算。
collapse (sum) total_bill tip, by(sex smoker)
pandas 提供了灵活的 groupby 机制,允许进行类似的聚合。有关更多详细信息和示例,请参阅 groupby documentation 。
转换#
在 Stata 中,如果需要将分组聚合与原始数据集一起使用,通常会使用带有 egen() 的 bysort。例如,按吸烟者组为每个观测值减去均值。
bysort sex smoker: egen group_bill = mean(total_bill)
generate adj_total_bill = total_bill - group_bill
pandas 提供了 转换 机制,可以简洁地用一个操作表达此类运算。
按组处理#
除了聚合,pandas 的 groupby 还可以用于复制 Stata 中大多数其他的 bysort 处理。例如,下面的示例按性别/吸烟者组列出当前排序顺序中的第一个观测值。
bysort sex smoker: list if _n == 1
在 pandas 中,这可以写成:
其他注意事项#
磁盘与内存#
pandas 和 Stata 都仅在内存中操作。这意味着 pandas 中能加载的数据量受限于您的机器内存。如果需要内存外处理,一种可能性是使用 dask.dataframe 库,该库为磁盘上的 DataFrame 提供了 pandas 功能的一个子集。