Python
Pandas Crosstab: 轻松分析的入门指南

Pandas Crosstab: 轻松分析的入门指南

MoeNagy Dev

什么是 pandas crosstab?

pandas 库中的 crosstab() 函数是一个强大的工具,用于创建列联表,也称为交叉表。它允许您分析两个或多个分类变量之间的关系,并以表格形式显示它们的频率分布。

crosstab() 函数以一个或多个系列或分类变量作为输入,生成一个二维表格,其中行表示一个变量,列表示另一个变量。生成的表格显示输入变量组合的计数或频率。

crosstab() 的主要特点和使用场景包括:

  • 频率分析: 识别不同分类变量组合的频率或计数。
  • 列联表: 创建列联表,以分析两个或多个分类变量之间的关系。
  • 透视表: 生成类似透视表的输出,可进一步自定义和分析。
  • 条件概率: 计算变量之间的条件概率。
  • 数据探索: 探索数据集中的分布和关系。

创建一个简单的 crosstab

让我们从生成一个示例 DataFrame 开始:

import pandas as pd
 
# 生成示例 DataFrame
data = {
    'Gender': ['Male', 'Female', 'Male', 'Female', 'Male', 'Female'],
    'Age': ['Young', 'Young', 'Old', 'Old', 'Young', 'Old'],
    'Count': [10, 8, 6, 12, 5, 9]
}
 
df = pd.DataFrame(data)

现在. , 我们可以使用 crosstab() 函数创建一个简单的交叉表:

pd.crosstab(df['Gender'], df['Age'])

这将输出一个表格,显示 DataFrame 中 'Gender' 和 'Age' 各组合的计数。

Age  Old  Young
Gender
Female   12     8
Male      6    15

行表示 'Gender' 变量,列表示 'Age' 变量。表格中的值显示了每个组合的计数。

自定义交叉表

您可以进一步自定义 crosstab() 函数以满足您的需求。让我们探索一些可用的选项。

指定行和列标签

您可以使用 indexcolumns 参数提供自定义的行和列标签:

pd.crosstab(df['Gender'], df['Age'], rownames=['Gender'], colnames=['Age'])

这将生成与之前相同的输出,但使用了自定义的行和列标签。

应用聚合函数

默认情况下,crosstab() 计算每个变量组合的出现次数。您可以通过使用 aggfunc 参数应用聚合函数来更改此行为:

pd.crosstab(df['Gender'], df['Age'], values=df['Count'], aggfunc=sum)

这将创建一个交叉表,对每个 'Gender' 和 'Age' 组合的 'Count' 值进行求和。

处理缺失值

如果您的数据包含缺失值,您可以使用 marginsmargins_name 参数来控制它们的处理方式:

pd.crosstab(df['Gender'], df['Age'], margins=True, margins_name='Total')

这将在交叉表中添加 'Total' 行和列,提供每行和每列的总计数,包括总体总计。

高级交叉表技术

处理多级索引

crosstab() 函数也可以处理数据中的多级索引。让我们创建一个具有多级索引的示例 DataFrame:

data = {
    ('Gender', ''): ['Male', 'Female', 'Male', 'Female', 'Male', '.
```python
data = {
    ('Gender', ''): ['Female', 'Female', 'Female', 'Female', 'Female', 'Female'],
    ('Age', ''): ['Young', 'Young', 'Old', 'Old', 'Young', 'Old'],
    ('Count', ''): [10, 8, 6, 12, 5, 9]
}
 
df = pd.DataFrame(data)
df.columns = pd.MultiIndex.from_tuples(df.columns)

现在,我们可以使用多级索引创建一个交叉表:

pd.crosstab(df[('Gender', '')], df[('Age', '')])

输出将具有行和列的多级索引,反映输入数据的结构。

规范化交叉表输出

您可以规范化交叉表输出,以显示相对频率而不是原始计数。这可以通过使用 normalize 参数来完成:

pd.crosstab(df['Gender'], df['Age'], normalize='index')

这将通过将每个值除以行和来规范化交叉表,从而得到行百分比。

可视化交叉表数据

要可视化交叉表数据,您可以使用 pandas 提供的各种绘图函数或其他可视化库,如 Matplotlib 或 Seaborn。例如:

import matplotlib.pyplot as plt
 
crosstab = pd.crosstab(df['Gender'], df['Age'])
crosstab.plot(kind='bar', figsize=(8, 6))
plt.title('性别和年龄的交叉表')
plt.xlabel('性别')
plt.ylabel('计数')
plt.show()

这将创建交叉表数据的条形图,有助于理解变量之间的关系。

过滤和排序交叉表

根据标准过滤交叉表

您可以使用标准的 pandas 索引和布尔掩码技术根据特定标准过滤交叉表:

crosstab = pd.crosstab(df['Gender'], df['Age'])
filtered_crosstab = crosstab.loc[crosstab['Young'] > 5]

这将创建一个新的交叉表,其中只包含 'Young' 列值大于 5 的行。

对交叉表行和列进行排序

要对交叉表的行和列进行排序,可以使用 sort_index() 方法:

crosstab = pd.crosstab(df['Gender'], df['Age'])
sorted_crosstab = crosstab.sort_index()

这将对交叉表的行和列进行排序。这将按降序对crosstab的行进行排序。

结合过滤和排序

您可以结合过滤和排序来进一步定制crosstab输出:

crosstab = pd.crosstab(df['Gender'], df['Age'])
filtered_sorted_crosstab = crosstab.loc[crosstab['Young'] > 5].sort_index(axis=0, ascending=False)

这将首先过滤crosstab,只包括'Young'列值大于5的行,然后按降序对行进行排序。

带有分类数据的Crosstabs

处理分类变量

在处理分类变量时,确保它们被正确编码为分类数据类型很重要。您可以使用astype()方法将列转换为分类数据类型:

df['Gender'] = df['Gender'].astype('category')
df['Age'] = df['Age'].astype('category')

显示分类特征的crosstab

一旦您设置好分类变量,就可以创建一个crosstab来分析它们之间的关系:

pd.crosstab(df['Gender'], df['Age'])

这将显示'Gender'和'Age'分类变量的crosstab。

处理分类数据中的NaN值

如果您的数据在分类变量中包含NaN(缺失)值,您可以使用dropna参数来处理它们:

pd.crosstab(df['Gender'], df['Age'], dropna=False)

这将在crosstab输出中包括NaN值,允许您分析缺失数据。

带有时间序列数据的Crosstabs

为基于时间的数据生成crosstabs

如果您的数据包含时间相关信息,您可以使用crosstab()函数来分析随时间的关系。让我们创建一个包含日期列的示例DataFrame:

data = {
    'Date': ['2022-01-01', '2022-01-02', '2022-01-03', '2022-01-04', '2022-01-05', '2022-01-06'],
    'Gender': ['Male', 'Female', 'Male', 'Female', 'Male', 'Female']
}
df = pd.DataFrame(data)
df['Date'] = pd.to_datetime(df['Date'])
data = {
    'Date': ['2022-01-01', '2022-01-02', '2022-01-03', '2022-01-04', '2022-01-05', '2022-01-06'],
    'Gender': ['Female', '男性', '女性', '男性', '女性', '男性'],
    'Age': ['年轻', '年轻', '老年', '老年', '年轻', '老年'],
    'Count': [10, 8, 6, 12, 5, 9]
}
 
df = pd.DataFrame(data)
# 将 'Date' 列转换为日期时间格式
df['Date'] = pd.to_datetime(df['Date'])

现在,您可以使用 'Date' 列作为变量之一创建一个交叉表:

# 创建一个交叉表,显示每个日期的性别计数
pd.crosstab(df['Date'].dt.date, df['Gender'])

这将生成一个交叉表,显示每个日期的每个性别的计数。

分析时间趋势和模式

您可以使用其他 pandas 函数或可视化来进一步分析基于时间的交叉表中的趋势和模式:

# 创建一个交叉表
crosstab = pd.crosstab(df['Date'].dt.date, df['Gender'])
# 绘制性别计数随时间的变化
crosstab.plot(kind='line', figsize=(10, 6))
plt.title('性别计数随时间变化')
plt.xlabel('日期')
plt.ylabel('计数')
plt.show()

这将创建一个线图,显示性别计数随时间的变化,帮助您识别数据中的任何趋势或模式。

处理日期/时间相关的操作

在处理基于时间的数据时,您可能需要执行各种日期/时间相关的操作,如按年、月或日分组。您可以使用 'Date' 列上的 dt 访问器来访问这些操作:

# 创建一个交叉表,显示每个月的性别计数
pd.crosstab(df['Date'].dt.month, df['Gender'])

这将创建一个交叉表,显示每个月的每个性别的计数。

将交叉表与其他 pandas 函数结合使用

将交叉表与 groupby() 结合使用

您可以将 crosstab() 函数与 groupby() 函数结合使用,执行更复杂的分析。例如,您可以先按变量对数据进行分组,然后在分组数据上创建交叉表:

# 按性别和年龄分组数据
grouped_df = df.groupby(['Gender', 'Age'])
# 创建一个交叉表,显示每个性别和年龄组合在每个日期的计数
pd.crosstab(grouped_df.groups.keys(), df['Date'].dt.date)

这将创建一个交叉表,显示每个性别和年龄组合在每个日期的计数。

将交叉表与 pivot_table() 结合使用

crosstab() 函数也可以与 pivot_table() 函数结合使用.使用 pivot_table() 函数进行更高级的数据分析:

pivot_table = pd.pivot_table(df, index=['Gender', 'Age'], columns='Date', values='Count', aggfunc='sum')

这将创建一个透视表,显示每个'Gender'和'Age'组合在不同日期的'Count'总和。

探索其他用于交叉表的 pandas 函数

虽然 crosstab() 是一个强大的工具,但还有其他 pandas 函数可以与之配合使用或作为替代方案。一些示例包括:

  • value_counts(): 获取 Series 中唯一值的频率计数。
  • pivot(): 创建类似电子表格的透视表作为 DataFrame。
  • melt(): 将宽格式的 DataFrame 转换为长格式。
  • cut()qcut(): 将连续数据划分为区间。

探索这些函数可以帮助您扩展数据分析工具箱,并找到最适合您特定用例的方法。

函数

函数是 Python 中的一个基本概念,它允许您封装一组指令并在整个代码中重复使用。函数可以接受输入参数,执行一些操作,并返回结果。

下面是一个简单的计算矩形面积的函数示例:

def calculate_area(length, width):
    area = length * width
    return area
 
# 调用函数并打印结果
result = calculate_area(5, 10)
print(f"The area of the rectangle is {result} square units.")

在这个例子中, calculate_area() 函数接受两个参数 lengthwidth,并返回计算出的面积。您可以调用该函数并将结果存储在 result 变量中,然后将其打印到控制台。

函数还可以有默认参数值,这允许您在不提供所有参数的情况下调用函数:

def greet(name, message="Hello"):
    print(f"{message}, {name}!")
 
greet("Alice")  # 输出: Hello, Alice!
greet("Bob", "Hi")  # 输出: Hi, Bob!
```这里是中文翻译版本:
 
```python
def greet(name, message="你好"):
    print(f"{message}, {name}!")
 
greet("Bob")  # 输出: 你好, Bob!

在这个例子中, greet() 函数的 message 参数有一个默认值 "你好", 所以你可以只传入 name 参数调用这个函数, 它会使用默认的问候语。

模块和包

Python 的模块化设计允许你将代码组织成可重复使用的组件, 称为模块。模块是包含函数、类和变量的 Python 文件, 可以在其他代码中导入和使用。

下面是一个简单的模块 math_utils.py 的例子:

def add(a, b):
    return a + b
 
def subtract(a, b):
    return a - b
 
def multiply(a, b):
    return a * b
 
def divide(a, b):
    return a / b

你可以在另一个 Python 文件中导入和使用这个模块中的函数:

import math_utils
 
result = math_utils.add(5, 3)
print(result)  # 输出: 8
 
result = math_utils.subtract(10, 4)
print(result)  # 输出: 6

模块也可以组织成包, 包是包含多个模块的目录。这允许你创建代码的层次结构, 使管理更加容易。

下面是一个包结构的例子:

my_package/
    __init__.py
    math/
        __init__.py
        operations.py
        geometry.py
    data/
        __init__.py
        file_utils.py
        database_utils.py

在这个例子中, my_package 包包含两个子包: mathdata。每个子包都有自己的一组模块, 而 __init__.py 文件允许 Python 将这些目录识别为包。

你可以从包中的模块导入和使用函数:

from my_package.math.operations import add, subtract
from my_package.data.file_utils import read_file
 
result = add(5, 3)
print(result)  # 输出: 8
 
data = read_file("data.txt")
print(data)

面向对象编程 (OOP)

面向对象编程 (OOP) 是一种编程范式, 它专注于创建对象. 对象是类的实例。类定义了对象的结构和行为,对象可以相互交互来解决复杂的问题。

下面是一个简单的表示人的类的例子:

class Person:
    # 初始化方法,用于设置对象的初始属性
    def __init__(self, name, age):
        self.name = name
        self.age = age
 
    # 打招呼的方法
    def greet(self):
        print(f"你好,我叫{self.name},今年{self.age}岁。")
 
# 创建一个 Person 对象并调用 greet 方法
person = Person("Alice", 30)
person.greet()  # 输出: 你好,我叫Alice,今年30岁。

在这个例子中,Person 类有两个属性(nameage)和一个方法(greet())。当创建一个新的 Person 对象时,可以使用 __init__() 方法设置属性的初始值,这个方法是一个特殊的构造方法。

你还可以创建继承自基类的子类,以扩展基类的功能:

class Student(Person):
    # 初始化方法,调用父类的初始化方法并添加新的属性
    def __init__(self, name, age, grade):
        super().__init__(name, age)
        self.grade = grade
 
    # 学习的方法
    def study(self):
        print(f"{self.name}正在学习{self.grade}年级的课程。")
 
# 创建一个 Student 对象并调用它的方法
student = Student("Bob", 15, "10th")
student.greet()  # 输出: 你好,我叫Bob,今年15岁。
student.study()  # 输出: Bob正在学习10th年级的课程。

在这个例子中,Student 类继承自 Person 类,添加了 grade 属性和 study() 方法。Student 类的 __init__() 方法使用 super() 函数调用了 Person 类的 __init__() 方法,以初始化 nameage 属性。

异常和错误处理

Python 的异常处理机制允许你处理代码中的意外情况,并提供一种优雅的方式来处理错误。当程序执行过程中出现错误时,会引发异常,你可以. 请编写代码来捕获和处理这些异常。

下面是一个如何处理 ZeroDivisionError 异常的示例:

def divide(a, b):
    try:
        result = a / b
        return result
    except ZeroDivisionError:
        print("错误: 不允许除以零。")
        return None
 
print(divide(10, 2))  # 输出: 5.0
print(divide(10, 0))  # 输出: 错误: 不允许除以零。

在这个示例中,divide() 函数使用 try-except 块来捕获 ZeroDivisionError 异常。如果除法操作引发了异常,则执行 except 块中的代码,并在控制台上打印一条消息。如果除法成功,则返回结果。

您还可以通过创建一个继承自内置 Exception 类的新类来定义自己的自定义异常:

class NegativeNumberError(Exception):
    pass
 
def square_root(number):
    if number < 0:
        raise NegativeNumberError("错误: 无法计算负数的平方根。")
    return number ** 0.5
 
try:
    print(square_root(16))  # 输出: 4.0
    print(square_root(-4))
except NegativeNumberError as e:
    print(e)  # 输出: 错误: 无法计算负数的平方根。

在这个示例中,square_root() 函数在输入数字为负数时引发自定义的 NegativeNumberError 异常。try-except 块捕获该异常并打印错误消息。

结论

在这个 Python 教程中,您已经学习了 Python 中的各种中级概念,包括函数、模块和包、面向对象编程以及异常处理。这些主题对于构建更复杂和更健壮的 Python 应用程序至关重要。

记住,提高 Python 技能的最佳方式是编写代码并解决问题。尝试使用本教程中提供的示例,并将这些概念应用到您自己的项目中。此外,继续学习和探索 Python 的更多功能和特性。探索广阔的 Python 库和框架生态系统,这可以大大扩展您的 Python 程序的功能。

祝您编码愉快!

MoeNagy Dev.