与SPSS的比较#

对于可能从SPSS迁移的用户,本页面旨在演示如何使用pandas执行各种SPSS操作。

如果您是 pandas 的新手,您可能需要先阅读10 分钟学会 pandas以熟悉该库。

按照惯例,我们如下导入 pandas 和 NumPy

In [1]: import pandas as pd

In [2]: import numpy as np

数据结构#

通用术语翻译#

pandas

SPSS

DataFrame

数据文件

变量

个案

groupby

拆分文件

NaN

系统缺失值

DataFrame#

pandas中的DataFrame类似于SPSS的数据文件——一个二维数据源,具有不同类型的带标签列。如本文档所示,几乎所有在SPSS中可以进行的操作,在pandas中也都可以完成。

Series#

Series是代表DataFrame一列的数据结构。SPSS没有单独的单个变量数据结构,但总体而言,处理Series类似于处理SPSS中的变量。

Index#

每个DataFrameSeries都有一个Index——数据的标签。SPSS没有完全对应的概念,因为个案只是从1开始顺序编号。在pandas中,如果未指定索引,则默认使用RangeIndex(第一行=0,第二行=1,依此类推)。

虽然使用带标签的IndexMultiIndex可以实现复杂的分析,并且最终是理解pandas的重要部分,但在本次比较中,我们将基本忽略Index,只将DataFrame视为一组列。请参阅索引文档以了解更多关于如何有效使用Index的信息。

副本与就地操作#

大多数 pandas 操作会返回 Series/DataFrame 的副本。要使更改“生效”,您需要将其分配给一个新变量

sorted_df = df.sort_values("col1")

或覆盖原始变量

df = df.sort_values("col1")

注意

您会发现某些方法提供了 inplace=Truecopy=False 关键字参数

df.replace(5, inplace=True)

关于弃用和删除大多数方法的 inplacecopy(例如 dropna),除了极少数方法(包括 replace)之外,正在积极讨论中。在 Copy-on-Write 的上下文中,这两个关键字将不再是必需的。提案可以在这里找到。

数据输入/输出#

读取外部数据#

与SPSS一样,pandas提供了读取多种格式数据的工具。在后续的许多示例中将使用pandas测试中包含的tips数据集(csv)。

在SPSS中,您将使用“文件”>“打开”>“数据”导入CSV文件。

FILE > OPEN > DATA
/TYPE=CSV
/FILE='tips.csv'
/DELIMITERS=","
/FIRSTCASE=2
/VARIABLES=col1 col2 col3.

pandas中对应的操作将使用read_csv()

url = (
    "https://raw.githubusercontent.com/pandas-dev"
    "/pandas/main/pandas/tests/io/data/csv/tips.csv"
)
tips = pd.read_csv(url)
tips

与SPSS的数据导入向导一样,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)

数据操作#

过滤#

在SPSS中,筛选是通过“数据”>“选择个案”完成的。

SELECT IF (total_bill > 10).
EXECUTE.

在pandas中,可以使用布尔索引。

tips[tips["total_bill"] > 10]

排序#

在SPSS中,排序是通过“数据”>“排序个案”完成的。

SORT CASES BY sex total_bill.
EXECUTE.

在pandas中,这将被写成:

tips.sort_values(["sex", "total_bill"])

字符串处理#

查找字符串长度#

在SPSS中

COMPUTE length = LENGTH(time).
EXECUTE.

您可以使用 Series.str.len() 查找字符字符串的长度。在 Python 3 中,所有字符串都是 Unicode 字符串。len 包括尾随空格。使用 lenrstrip 来排除尾随空格。

In [3]: tips["time"].str.len()
Out[3]: 
67     6
92     6
111    6
145    5
135    5
      ..
182    6
156    6
59     6
212    6
170    6
Name: time, Length: 244, dtype: int64

In [4]: tips["time"].str.rstrip().str.len()
Out[4]: 
67     6
92     6
111    6
145    5
135    5
      ..
182    6
156    6
59     6
212    6
170    6
Name: time, Length: 244, dtype: int64

更改大小写#

在SPSS中

COMPUTE upper = UPCASE(time).
COMPUTE lower = LOWER(time).
EXECUTE.

等效的 pandas 方法是 Series.str.upper()Series.str.lower()Series.str.title()

In [5]: firstlast = pd.DataFrame({"string": ["John Smith", "Jane Cook"]})

In [6]: firstlast["upper"] = firstlast["string"].str.upper()

In [7]: firstlast["lower"] = firstlast["string"].str.lower()

In [8]: firstlast["title"] = firstlast["string"].str.title()

In [9]: firstlast
Out[9]: 
       string       upper       lower       title
0  John Smith  JOHN SMITH  john smith  John Smith
1   Jane Cook   JANE COOK   jane cook   Jane Cook

合并#

在SPSS中,合并数据文件是通过“数据”>“合并文件”完成的。

以下表格将用于合并示例

In [10]: df1 = pd.DataFrame({"key": ["A", "B", "C", "D"], "value": np.random.randn(4)})

In [11]: df1
Out[11]: 
  key     value
0   A  0.469112
1   B -0.282863
2   C -1.509059
3   D -1.135632

In [12]: df2 = pd.DataFrame({"key": ["B", "D", "D", "E"], "value": np.random.randn(4)})

In [13]: df2
Out[13]: 
  key     value
0   B  1.212112
1   D -0.173215
2   D  0.119209
3   E -1.044236

pandas DataFrame 有一个 merge() 方法,它提供了类似的功能。数据不必提前排序,并且可以通过 how 关键字实现不同的连接类型。

In [14]: inner_join = df1.merge(df2, on=["key"], how="inner")

In [15]: inner_join
Out[15]: 
  key   value_x   value_y
0   B -0.282863  1.212112
1   D -1.135632 -0.173215
2   D -1.135632  0.119209

In [16]: left_join = df1.merge(df2, on=["key"], how="left")

In [17]: left_join
Out[17]: 
  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 [18]: right_join = df1.merge(df2, on=["key"], how="right")

In [19]: right_join
Out[19]: 
  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 [20]: outer_join = df1.merge(df2, on=["key"], how="outer")

In [21]: outer_join
Out[21]: 
  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

GroupBy操作#

拆分文件处理#

在SPSS中,拆分文件分析是通过“数据”>“拆分文件”完成的。

SORT CASES BY sex.
SPLIT FILE BY sex.
DESCRIPTIVES VARIABLES=total_bill tip
  /STATISTICS=MEAN STDDEV MIN MAX.

pandas中的对应操作将是:

tips.groupby("sex")[["total_bill", "tip"]].agg(["mean", "std", "min", "max"])

缺失数据#

SPSS使用句点(.)表示数值缺失值,使用空格表示字符串缺失值。pandas使用NaN(非数字)表示数值缺失值,使用NoneNaN表示字符串缺失值。

在 pandas 中,可以使用 Series.isna()Series.notna() 来过滤行。

In [22]: outer_join[outer_join["value_x"].isna()]
Out[22]: 
  key  value_x   value_y
5   E      NaN -1.044236

In [23]: outer_join[outer_join["value_x"].notna()]
Out[23]: 
  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 提供了多种处理缺失数据的方法。以下是一些示例

删除包含缺失值的行#

In [24]: outer_join.dropna()
Out[24]: 
  key   value_x   value_y
1   B -0.282863  1.212112
3   D -1.135632 -0.173215
4   D -1.135632  0.119209

从前一行向前填充#

In [25]: outer_join.ffill()
Out[25]: 
  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

用指定值替换缺失值#

使用平均值

In [26]: outer_join["value_x"].fillna(outer_join["value_x"].mean())
Out[26]: 
0    0.469112
1   -0.282863
2   -1.509059
3   -1.135632
4   -1.135632
5   -0.718815
Name: value_x, dtype: float64

其他注意事项#

输出管理#

虽然pandas没有直接等同于SPSS的输出管理系统(OMS),但您可以通过多种方式捕获和导出结果。

# Save summary statistics to CSV
tips.groupby('sex')[['total_bill', 'tip']].mean().to_csv('summary.csv')

# Save multiple results to Excel sheets
with pd.ExcelWriter('results.xlsx') as writer:
    tips.describe().to_excel(writer, sheet_name='Descriptives')
    tips.groupby('sex').mean().to_excel(writer, sheet_name='Means by Gender')