此前我使用 R 处理数据,对 R base 和 data.table 包较为熟悉。现在着手学习 python,从使用 pandas 处理数据开始。下面简单地梳理一组对照关系。
|-|R|Python| |:–:|:–:| |基础数值计算|R base|内置函数、numpy| |数据处理|data.table|pandas|
R base 中的向量与 pandas 中的一维数组 🔗
以下是 R base 中创建向量、查看元素、用分位数函数计算的代码与输出结果。
```r
series <- c(1:24) # 创建一个向量
print(series) # 打印
```
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
```r
series[0] # 查看索引为0的元素
```
integer(0)
```r
series[1:3] # 查看索引为1到3的元素
```
[1] 1 2 3
```r
quantile(series[1:10], probs = c(0.25, 0.75)) # 计算前10个元素的25%和75%的分位数
```
25% 75%
3.25 7.75
接下来使用 python 的 pandas 来对照实现。
```python
import pandas as pd
series = pd.Series(range(1,25)) # 创建一个一维数组
print(series) # 打印
```
0 1
1 2
...
22 23
23 24
dtype: int64
```python
series[0]
```
np.int64(1)
```python
series[1:3]
```
1 2
2 3
dtype: int64
```python
series[1:10].quantile([0.25, 0.75])
```
0.25 4.0
0.75 8.0
dtype: float64
对照来看,两者的主要区别在于使用函数的方式。R 中创建了一个向量 series,使用quantile(series)计算分位数,这种函数名(向量)用法是函数作为一个工具,将向量输入函数,然后输出函数作用后的结果。而在 Python 中创建了一个一维数组 series,作为一个数据对象,pandas 提供给 series 很多功能(或称属性),执行series.quantile()就是调用了 series 这个对象的quantile()功能,这种对象.函数名()的用法主体是对象。在使用函数的性质这点上,前者像是用工具,后者像是用功能。其他存在于两者之间的差异如下。
- 区间封闭差异
- R 中区间包含末尾,如向量
c(1:24)包含24。 - Python 中区间不包含末尾,如
range(1, 24)不包含24,series[1:3]会只查看索引序号为1到2的元素。
- 索引序号差异
- R 中数据对象的索引序号从1开始。
- Python 则从0开始。
- 符号差异
- 表示向量
- R 中使用
c()创建向量,比如c(0.25, 0.75)。 - Python 中用
[]表示向量,如[0.25, 0.75]。
- R 中使用
- 表示区间
- R 中使用
:表示区间,比如执行1:24得到1到24个数字;也表示索引切片,如series[1:24]会查看索引为1到24的元素。 - Python 中直接执行
1:24会报错,仅仅在索引时用:表示切片,比如series[1:24]会查看索引为1到23的元素。
- R 中使用
- 赋值符号
- R 中给对象赋值用
<-。 - Python 中给对象赋值用
=。
- R 中给对象赋值用
R base 中的列表与 Python 中的列表、字典 🔗
以下是 R base 中创建一个列表,然后查看列表中的元素。R 的列表有以下几个特点。
- 列表的元素可以是任意类型。
- 列表的元素可以是不同长度。
- 列表中可以嵌套列表。
- 列表中的元素可以有名字,或者没有名字,索引序号从1开始。
- 分别用
[]按索引序号查看子列表,用[[]]按索引序号查看元素内容,用$按名称查看子列表。
r_list <- list(c(1:24),
col2 = LETTERS[1:6],
col3 = list(a = 1:2, b = list(c(1, 2, 'b'))))
r_list[2] # 按索引序号查看第2个子列表,得到一个列表
r_list[[2]] # 按索引序号查看第2个元素,对应得到一个向量
r_list['col2'] # 按元素名称查看子列表
r_list[["col2"]] # 按元素名称查看对应元素内容
r_list$col3$b # 按元素名称查看嵌套列表
r_list[[3]][[2]][[1]] # 按索引序号查看层层嵌套的元素内容
以下是对照在 Python 中创建近似的列表和字典。与 R 列表相同的是:任意元素类型、元素长度不同、可以嵌套。而有区别的是以下几点。
- R 列表中元素可以有名或无名,python 列表中元素无名,python 字典中元素都必须有名称。
- R 列表支持用索引序号或名称查看元素,python 列表仅支持用索引序号,而 python 字典仅支持用名称。
- R 列表用
list()来创建,而 python 列表用[],python 字典用{}。 - R 列表可以查看子列表或元素内容,而 python 列表或字典均是直接查看元素内容。
- R 中如
c(1,2,'b')同时有数值和字符串创建向量时,会把数值转换成字符串,而 python 列表或字典会保持原样。 - R 中分别用
[]、[[]]、$在不同情况查看元素,而 python 列表和字典统一用[]查看元素。
p_list = [range(1, 25), list("ABCDEF"),
[
[1, 2],
[[1, 2, 'b']]
]]
p_list[1] # 得到 ['A', 'B', 'C', 'D', 'E', 'F']
p_list[2][1][0][1]+1 # 得到 3
p_dict = {
"col1": range(1, 25),
"col2": list("ABCDEF"),
"col3": {
"a": [1, 2],
"b": [[1, 2, 'b']]
}
}
p_dict["col2"] # 得到 ['A', 'B', 'C', 'D', 'E', 'F']
p_dict["col3"]["b"] # 得到 [[1, 2, 'b']]
p_dict["col3"]["b"][0] # 得到 [[1, 2, 'b']]
p_dict["col3"]["b"][0][1] # 得到 2
data.table 与 pandas 的数据框 🔗
以下是 R data.table 创建一个数据框。
library(data.table)
set.seed(2023)
dt <-
data.table(
column1 = c(1:24),
column2 = rep(LETTERS[1:6], 4),
column3 = sample(1:100, 24),
column4 = sample(50:100, 24)
)
head(dt)
以下是 Python 中创建一个同样的数据框。
import pandas as pd
import numpy as np
np.random.seed(2023)
data = {
"column1": np.arange(1, 25), # 1 到 24
"column2": np.tile(list("ABCDEF"), 4), # 重复 A-F 共 4 次
"column3": np.random.randint(1, 101, 24), # 1~100 随机数
"column4": np.random.randint(50, 101, 24) # 50~100 随机数
}
df = pd.DataFrame(data)
df.head()
除了前几小节中的差异,两种语言在数据框之间还有更多差异,总结如下。
- 加载 vs 导入
- R 加载包,该包中所有函数都会被一次性全部加载到全局空间中。
- Python 导入包,可以导入整个包,也可以只导入包中部分函数或模块。
- 使用函数
- R 中
- 加载包以后,包中的函数都可以直接使用,比如用
data.table()创建一个数据对象。 - 嵌套使用多层函数,比如
rep(LETTERS[1:6], 4)。
- 加载包以后,包中的函数都可以直接使用,比如用
- Python 中
- 使用内置函数时,用法与 R 一致,比如
print(df)打印数据框。 - 使用包中的函数时,需要加上包名作为前缀,比如用
pd.DataFrame()创建一个数据对象。 - 指定对象来使用函数的功能时,加上对象名作为前缀,如
df.head()查看数据框前6行。 - 嵌套使用多层函数时,用
.的方式像链条一样层层调用指定函数,如df.head(6).min()。
- 使用内置函数时,用法与 R 一致,比如
接下来,通过筛选行和列来比较两者差异。data.table 在筛选行列上语法极为简洁、统一,而 pandas 相比之下更加复杂,且有三种方式要进行区分,即df[...],df.iloc[...](ps指 integer location,按索引序号这样的整数代表位置),df.loc[...](ps指 location,按名称代表位置)。需要注意的是,当行的索引默认为从0开始的数字时,df.iloc[0:2]取出索引序号为切片0:2之间的行,由于python区间左闭右开的特点,实际上取出的是第1、2行;此时数据框的标签也是数字,df.loc[0:2]取出的是标签数字为0:2之间的行,那么实际取出第1、2、3行。
以下分别按序号、名称、条件筛选行或列,同时筛选行和列等方式来梳理三者之间的区别。
- 筛选行
df[...]- 按序号: √ 支持按行切片,比如
df[0:2]。不支持df[0],这代表取出列名称为0的列。 - 按名称: × 不支持。
- 按条件: √ 支持。比如多条件
df[(df["column1"] <= 3) & (df["column2"] != "B")]。
- 按序号: √ 支持按行切片,比如
df.iloc[...]- 按序号: √ 支持。比如
df.iloc[0],df.iloc[0:2],df.iloc[[0,2,4]]。 - 按名称: × 不支持。
- 按条件: × 不支持。
- 按序号: √ 支持。比如
df.loc[...]- 按序号: × 不支持。
- 按名称: √ 支持。
- 按条件: √ 支持。比如
df.loc[df["column1"] <= 3]。
- 筛选列
df[...]- 按序号: × 不支持。
- 按名称: √ 支持。比如
df["column1"],df[["column1","column3"]]。 - 按条件: × 不支持。
df.iloc[...]- 按序号: √ 支持。比如
df.iloc[:, 0],df.iloc[:, [0,1,3]]`。 - 按名称: × 不支持。
- 按条件: × 不支持。
- 按序号: √ 支持。比如
df.loc[...]- 按序号: × 不支持。
- 按名称: √ 支持。比如
df.loc[:, "column1"],df.loc[:, ["column1", "column2"]]。 - 按条件: √ 支持。比如
cols = df.columns[df.columns.str.contains("col")] df.loc[:, cols]。
- 同时筛选行和列
df[...]: × 不支持。df.iloc[...]: √ 支持。比如按序号,df.iloc[0:2, 0:3]df.loc[...]: √ 支持。比如按条件或名称,df.loc[df["column2"].isin(["B", "C"]), ["column2", "column3"]]。
以下是练习两种语言下筛选数据框的操作。
| - | R data.table | Python pandas |
|---|---|---|
| 按序号筛选一行 | dt[1] |
df.iloc[0] |
| 按序号筛选多行 | dt[7:9] |
df.iloc[6:9] |
| 单条件筛选行 | dt[column1 <= 3] |
df[df["column1"] <= 3] |
| 多条件筛选行 | dt[column1 <= 3 & !(column2 == 'B')] |
df[(df["column1"] <= 3) & (df["column2"] != "B")] |
| 按序号筛选单列 | dt[, 1] |
df.iloc[:, 0] |
| 按序号筛选多列 | dt[, c(1:2, 4)] |
df.iloc[:, [0,1,3]] |
| 按序号去掉一列 | dt[,-2] |
df.drop(df.columns[1], axis=1) |
| 按序号去掉多列 | dt[, -c(2, 4)] |
df.drop(df.columns[[1, 3]], axis=1) |
| 按名称筛选列 | dt[, 'column1'] |
df["column1"] |
| 按名称筛选多列 | dt[, c('column1','column3')] |
df[["column1","column3"]] |
| 按名称去掉多列 | dt[, -c('column1','column3')] |
df.drop(columns=["column1","column3"]) |
| 按序号筛选行和列 | dt[1:2, 1:3] |
df.iloc[0:2, 0:3] |
| 按条件和名称筛选行和列 | dt[column2 %in% c('B', 'C'), c('column2', 'column3')] |
df.loc[df["column2"].isin(["B", "C"]), ["column2", "column3"]] |
附录 🔗
快捷键不快捷:对比 Rstudio、Pycharm、vscode 🔗
操作系统、各类软件为了便于操作都会设置一些快捷键,但是对于本新手这是个沉重的负担。首先讲操作系统,公司里本地电脑是 UOS,服务器是 Linux,家里电脑是 Windows。然后讲各软件,操作数据库有不同的 IDE,用 R 是 Rstudio,用 Python 是 Pycharm,这次时间充裕从头学 Python 改用 vscode。最后软件和系统的快捷键偶尔还会冲突。所以整个全能 AI 助手多么好,但……
- RStudio
- 执行选中代码:Ctrl + Enter
- 代码格式化:Ctrl + Shift + A
- 批量加注释:Ctrl + Shift + C
- Pycharm
- 执行选中代码: shift + alt +E
- 代码格式化:ctrl + alt +L
- 批量加注释:ctrl + /
vscode 我现在调试 AI 写的代码创建.py文件,边学边记笔记是用其中的 jupyter notebook 插件。操作上还玩不溜……
- 切换终端,vscode 打开后默认终端是 bash,那么直接输入
R会切换到 R 环境,而输入Python3会切换到 Python 环境。 - 设置 Shift + Enter 为将选中代码发送到终端执行。在vscode左下角找到“管理”(ps机械齿轮图标)单击
键盘快捷方式,搜索关键词如“run selected text”找到“终端: 在活动终端运行所选文本(“command”: “workbench.action.terminal.runSelectedText”)”,然后设置好快捷键。 - 选中代码格式化: Ctrl + K Ctrl + F。
- 批量加注释:ctrl + /
好翻的文档 🔗
- data.table 与 pandas:https://cosx.org/2021/01/dt-pd/。
- pandas 菜鸟教程:https://www.runoob.com/pandas/pandas-intro.html。
- pandas 官方手册:https://pandas.pydata.org/docs/reference/index.html。
最后,因为会 sql 和 R,处理数据要做的事其实差不多,换到 Python 里面大概就是函数名称变了,或者用函数的方式变了。不过搞清楚区别以后,到了做事这一步就是自然的积累过程,现在 AI 写的代码也还不错,所以只需要搞清楚换语言后的关键差异,能看懂 AI 的代码然后举一反三就可以了。记住函数名称的步骤感觉可以省略,反正可以让 AI 解释。如此大言不惭,这该不会就是俺一直是个新手的原因吧,哈哈。