Pandas GroupBy 和 Shift 操作:高效数据分析的关键技巧

Pandas GroupBy 和 Shift 操作:高效数据分析的关键技巧

参考:pandas groupby shift

Pandas 是一个强大的 Python 数据分析库,它提供了许多用于处理结构化数据的工具和函数。在数据分析过程中,GroupBy 和 Shift 操作是两个非常重要的功能,它们可以帮助我们更有效地处理和分析数据。本文将详细介绍 Pandas 中的 GroupBy 和 Shift 操作,并通过多个示例来展示它们的用法和应用场景。

1. GroupBy 操作简介

GroupBy 操作是 Pandas 中一个非常重要的功能,它允许我们将数据按照某个或某些列进行分组,然后对每个分组应用特定的操作。这种操作在数据分析中非常常见,例如计算每个类别的平均值、找出每个组的最大值等。

1.1 基本用法

让我们从一个简单的例子开始,了解 GroupBy 的基本用法:

import pandas as pd

# 创建示例数据
data = {
    'name': ['Alice', 'Bob', 'Charlie', 'Alice', 'Bob', 'Charlie'],
    'score': [85, 92, 78, 90, 88, 95],
    'subject': ['Math', 'Math', 'Math', 'English', 'English', 'English']
}
df = pd.DataFrame(data)

# 按 name 列进行分组,并计算每个人的平均分数
result = df.groupby('name')['score'].mean()
print("Average scores from pandasdataframe.com:")
print(result)

Output:

Pandas GroupBy 和 Shift 操作:高效数据分析的关键技巧

在这个例子中,我们首先创建了一个包含学生姓名、分数和科目的 DataFrame。然后,我们使用 groupby('name') 按照姓名进行分组,并计算每个人的平均分数。这个操作会返回一个 Series,其中索引是姓名,值是对应的平均分数。

1.2 多列分组

GroupBy 操作也支持多列分组,这在处理更复杂的数据结构时非常有用:

import pandas as pd

# 创建示例数据
data = {
    'name': ['Alice', 'Bob', 'Charlie', 'Alice', 'Bob', 'Charlie'],
    'score': [85, 92, 78, 90, 88, 95],
    'subject': ['Math', 'Math', 'Math', 'English', 'English', 'English'],
    'school': ['A', 'B', 'A', 'A', 'B', 'A']
}
df = pd.DataFrame(data)

# 按 school 和 subject 列进行分组,并计算每个组的平均分数
result = df.groupby(['school', 'subject'])['score'].mean()
print("Average scores by school and subject from pandasdataframe.com:")
print(result)

Output:

Pandas GroupBy 和 Shift 操作:高效数据分析的关键技巧

在这个例子中,我们按照学校和科目进行分组,然后计算每个组的平均分数。结果是一个多级索引的 Series,其中第一级索引是学校,第二级索引是科目。

1.3 聚合函数

GroupBy 操作支持多种聚合函数,不仅限于平均值。我们可以使用 agg 方法同时应用多个聚合函数:

import pandas as pd

# 创建示例数据
data = {
    'name': ['Alice', 'Bob', 'Charlie', 'Alice', 'Bob', 'Charlie'],
    'score': [85, 92, 78, 90, 88, 95],
    'subject': ['Math', 'Math', 'Math', 'English', 'English', 'English']
}
df = pd.DataFrame(data)

# 按 name 列进行分组,并应用多个聚合函数
result = df.groupby('name')['score'].agg(['mean', 'min', 'max', 'count'])
print("Score statistics from pandasdataframe.com:")
print(result)

Output:

Pandas GroupBy 和 Shift 操作:高效数据分析的关键技巧

在这个例子中,我们对每个人的分数同时计算了平均值、最小值、最大值和计数。结果是一个 DataFrame,其中列名是聚合函数的名称。

1.4 自定义聚合函数

除了内置的聚合函数,我们还可以使用自定义函数进行聚合:

import pandas as pd

# 创建示例数据
data = {
    'name': ['Alice', 'Bob', 'Charlie', 'Alice', 'Bob', 'Charlie'],
    'score': [85, 92, 78, 90, 88, 95],
    'subject': ['Math', 'Math', 'Math', 'English', 'English', 'English']
}
df = pd.DataFrame(data)

# 自定义聚合函数:计算分数范围
def score_range(x):
    return x.max() - x.min()

# 按 name 列进行分组,并应用自定义聚合函数
result = df.groupby('name')['score'].agg(['mean', score_range])
print("Score statistics with custom function from pandasdataframe.com:")
print(result)

Output:

Pandas GroupBy 和 Shift 操作:高效数据分析的关键技巧

在这个例子中,我们定义了一个 score_range 函数来计算分数的范围(最高分和最低分之差)。然后,我们将这个自定义函数与内置的 mean 函数一起应用到分组后的数据上。

2. Shift 操作简介

Shift 操作是另一个在数据分析中非常有用的功能。它允许我们将数据在时间序列或其他序列中移动,这在计算变化率、滞后效应等场景中非常有用。

2.1 基本用法

让我们从一个简单的例子开始,了解 Shift 的基本用法:

import pandas as pd

# 创建示例数据
data = {
    'date': pd.date_range(start='2023-01-01', periods=5),
    'value': [100, 102, 98, 105, 103]
}
df = pd.DataFrame(data)

# 使用 shift 操作
df['previous_value'] = df['value'].shift(1)
print("Data with shifted values from pandasdataframe.com:")
print(df)

Output:

Pandas GroupBy 和 Shift 操作:高效数据分析的关键技巧

在这个例子中,我们创建了一个包含日期和值的 DataFrame。然后,我们使用 shift(1) 操作创建了一个新列 previous_value,它包含了 value 列向下移动一位的结果。这样,每一行的 previous_value 就是前一天的值。

2.2 计算变化率

Shift 操作常用于计算变化率,例如日收益率:

import pandas as pd

# 创建示例数据
data = {
    'date': pd.date_range(start='2023-01-01', periods=5),
    'price': [100, 102, 98, 105, 103]
}
df = pd.DataFrame(data)

# 计算日收益率
df['daily_return'] = (df['price'] / df['price'].shift(1) - 1) * 100
print("Daily returns from pandasdataframe.com:")
print(df)

Output:

Pandas GroupBy 和 Shift 操作:高效数据分析的关键技巧

在这个例子中,我们使用 Shift 操作来计算每日的收益率。公式为 (当日价格 / 前一日价格 - 1) * 100,这给出了以百分比表示的日收益率。

2.3 不同方向的 Shift

Shift 操作可以向前或向后移动数据:

import pandas as pd

# 创建示例数据
data = {
    'date': pd.date_range(start='2023-01-01', periods=5),
    'value': [100, 102, 98, 105, 103]
}
df = pd.DataFrame(data)

# 向后移动一位
df['next_value'] = df['value'].shift(-1)

# 向前移动两位
df['two_days_ago'] = df['value'].shift(2)

print("Data with different shifts from pandasdataframe.com:")
print(df)

Output:

Pandas GroupBy 和 Shift 操作:高效数据分析的关键技巧

在这个例子中,我们展示了如何使用正值和负值来控制 Shift 的方向和步数。shift(-1) 将数据向上移动一位,相当于获取下一个值;shift(2) 将数据向下移动两位,相当于获取两天前的值。

3. GroupBy 和 Shift 的结合使用

GroupBy 和 Shift 操作的结合使用可以帮助我们解决更复杂的数据分析问题,特别是在处理分组时间序列数据时。

3.1 分组计算滞后值

我们可以在每个组内应用 Shift 操作:

import pandas as pd

# 创建示例数据
data = {
    'date': pd.date_range(start='2023-01-01', periods=10),
    'group': ['A', 'B'] * 5,
    'value': [100, 95, 102, 98, 104, 97, 101, 99, 103, 96]
}
df = pd.DataFrame(data)

# 在每个组内应用 shift 操作
df['previous_value'] = df.groupby('group')['value'].shift(1)
print("Data with grouped shift from pandasdataframe.com:")
print(df)

Output:

Pandas GroupBy 和 Shift 操作:高效数据分析的关键技巧

在这个例子中,我们首先创建了一个包含日期、分组和值的 DataFrame。然后,我们使用 groupby('group') 按组进行分组,并在每个组内应用 shift(1) 操作。这样,我们就得到了每个组内的前一个值,而不是整个 DataFrame 的前一个值。

3.2 分组计算变化率

我们可以结合 GroupBy 和 Shift 来计算每个组内的变化率:

import pandas as pd

# 创建示例数据
data = {
    'date': pd.date_range(start='2023-01-01', periods=10),
    'group': ['A', 'B'] * 5,
    'value': [100, 95, 102, 98, 104, 97, 101, 99, 103, 96]
}
df = pd.DataFrame(data)

# 计算每个组内的变化率
df['change_rate'] = df.groupby('group')['value'].pct_change() * 100
print("Change rates within groups from pandasdataframe.com:")
print(df)

Output:

Pandas GroupBy 和 Shift 操作:高效数据分析的关键技巧

在这个例子中,我们使用 groupby('group') 按组进行分组,然后使用 pct_change() 方法计算每个组内的百分比变化。pct_change() 方法内部使用了 Shift 操作来计算相邻值之间的变化率。

3.3 滚动计算

我们可以结合 GroupBy 和 Shift 来进行滚动计算,例如计算每个组内的移动平均:

import pandas as pd

# 创建示例数据
data = {
    'date': pd.date_range(start='2023-01-01', periods=10),
    'group': ['A', 'B'] * 5,
    'value': [100, 95, 102, 98, 104, 97, 101, 99, 103, 96]
}
df = pd.DataFrame(data)

# 计算每个组内的3天移动平均
df['moving_avg'] = df.groupby('group')['value'].rolling(window=3).mean().reset_index(level=0, drop=True)
print("Moving averages within groups from pandasdataframe.com:")
print(df)

Output:

Pandas GroupBy 和 Shift 操作:高效数据分析的关键技巧

在这个例子中,我们首先按组进行分组,然后使用 rolling(window=3) 创建一个3天的滚动窗口,并计算窗口内的平均值。reset_index(level=0, drop=True) 用于重置索引,使结果与原始 DataFrame 对齐。

3.4 计算累积和

我们可以使用 GroupBy 和 Shift 来计算每个组内的累积和:

import pandas as pd

# 创建示例数据
data = {
    'date': pd.date_range(start='2023-01-01', periods=10),
    'group': ['A', 'B'] * 5,
    'value': [10, 15, 20, 25, 30, 35, 40, 45, 50, 55]
}
df = pd.DataFrame(data)

# 计算每个组内的累积和
df['cumulative_sum'] = df.groupby('group')['value'].cumsum()
print("Cumulative sums within groups from pandasdataframe.com:")
print(df)

Output:

Pandas GroupBy 和 Shift 操作:高效数据分析的关键技巧

在这个例子中,我们使用 groupby('group') 按组进行分组,然后使用 cumsum() 方法计算每个组内的累积和。这个操作实际上是在每个组内进行的,所以每个组的累积和是独立计算的。

3.5 计算组内排名

我们可以使用 GroupBy 和 Shift 来计算每个组内的排名:

import pandas as pd

# 创建示例数据
data = {
    'date': pd.date_range(start='2023-01-01', periods=10),
    'group': ['A', 'B'] * 5,
    'value': [100, 95, 102, 98, 104, 97, 101, 99, 103, 96]
}
df = pd.DataFrame(data)

# 计算每个组内的排名
df['rank'] = df.groupby('group')['value'].rank(method='dense', ascending=False)
print("Rankings within groups from pandasdataframe.com:")
print(df)

Output:

Pandas GroupBy 和 Shift 操作:高效数据分析的关键技巧

在这个例子中,我们使用 groupby('group') 按组进行分组,然后使用 rank() 方法计算每个组内的排名。method='dense' 参数指定了排名方法,ascending=False 参数指定了排序方式为降序。

3.6 计算组内差异

我们可以使用 GroupBy 和 Shift 来计算每个组内相邻值之间的差异:

import pandas as pd

# 创建示例数据
data = {
    'date': pd.date_range(start='2023-01-01', periods=10),
    'group': ['A', 'B'] * 5,
    'value': [100, 95, 102, 98, 104, 97, 101, 99, 103, 96]
}
df = pd.DataFrame(data)

# 计算每个组内相邻值之间的差异
df['diff'] = df.groupby('group')['value'].diff()
print("Differences within groups from pandasdataframe.com:")
print(df)

Output:

Pandas GroupBy 和 Shift 操作:高效数据分析的关键技巧

在这个例子中,我们使用 groupby('group') 按组进行分组,然后使用 diff() 方法计算每个组内相邻值之间的差异。这个操作会计算每个值与其前一个值之间的差,第一个值的差异为 NaN。

3.7 计算组内累积最大值

我们可以使用 GroupBy 和 Shift 来计算每个组内的累积最大值:

import pandas as pd

# 创建示例数据
data = {
    'date': pd.date_range(start='2023-01-01', periods=10),
    'group': ['A', 'B'] * 5,
    'value': [100, 95, 102, 98, 104, 97, 101, 99, 103, 96]
}
df = pd.DataFrame(data)

# 计算每个组内的累积最大值
df['cummax'] = df.groupby('group')['value'].cummax()
print("Cumulative maximum within groups from pandasdataframe.com:")
print(df)

Output:

Pandas GroupBy 和 Shift 操作:高效数据分析的关键技巧

在这个例子中,我们使用 groupby('group') 按组进行分组,然后使用 cummax() 方法计算每个组内的累积最大值。这个操作会返回到目前为止观察到的最大值。

3.8 计算组内滚动相关性

我们可以使用 GroupBy 和 Shift 来计算组内两个变量之间的滚动相关性:

import pandas as pd
import numpy as np

# 创建示例数据
np.random.seed(0)
data = {
    'date': pd.date_range(start='2023-01-01', periods=20),
    'group': ['A', 'B'] * 10,
    'value1': np.random.randn(20),
    'value2': np.random.randn(20)
}
df = pd.DataFrame(data)

# 计算每个组内的滚动相关性
df['rolling_corr'] = df.groupby('group').apply(lambda x: x['value1'].rolling(window=5).corr(x['value2'])).reset_index(level=0, drop=True)
print("Rolling correlation within groups from pandasdataframe.com:")
print(df)

在这个例子中,我们首先创建了一个包含两个随机值列的 DataFrame。然后,我们使用 groupby('group') 按组进行分组,并应用一个 lambda 函数来计算 ‘value1’ 和 ‘value2’ 之间的滚动相关性。我们使用 5 天的窗口进行计算。

3.9 计算组内百分比排名

我们可以使用 GroupBy 和 Shift 来计算每个组内的百分比排名:

import pandas as pd

# 创建示例数据
data = {
    'date': pd.date_range(start='2023-01-01', periods=10),
    'group': ['A', 'B'] * 5,
    'value': [100, 95, 102, 98, 104, 97, 101, 99, 103, 96]
}
df = pd.DataFrame(data)

# 计算每个组内的百分比排名
df['percent_rank'] = df.groupby('group')['value'].rank(pct=True)
print("Percent rank within groups from pandasdataframe.com:")
print(df)

Output:

Pandas GroupBy 和 Shift 操作:高效数据分析的关键技巧

在这个例子中,我们使用 groupby('group') 按组进行分组,然后使用 rank(pct=True) 方法计算每个组内的百分比排名。这个操作会返回一个 0 到 1 之间的值,表示每个值在其组内的相对位置。

3.10 计算组内移动中位数

我们可以使用 GroupBy 和 Shift 来计算每个组内的移动中位数:

import pandas as pd

# 创建示例数据
data = {
    'date': pd.date_range(start='2023-01-01', periods=15),
    'group': ['A', 'B', 'C'] * 5,
    'value': [100, 95, 102, 98, 104, 97, 101, 99, 103, 96, 105, 94, 100, 98, 102]
}
df = pd.DataFrame(data)

# 计算每个组内的3天移动中位数
df['moving_median'] = df.groupby('group')['value'].rolling(window=3).median().reset_index(level=0, drop=True)
print("Moving median within groups from pandasdataframe.com:")
print(df)

Output:

Pandas GroupBy 和 Shift 操作:高效数据分析的关键技巧

在这个例子中,我们首先按组进行分组,然后使用 rolling(window=3) 创建一个3天的滚动窗口,并计算窗口内的中位数。reset_index(level=0, drop=True) 用于重置索引,使结果与原始 DataFrame 对齐。

4. 高级应用场景

现在我们已经掌握了 GroupBy 和 Shift 操作的基本用法,让我们来看一些更复杂的应用场景。

4.1 时间序列分析

在时间序列分析中,GroupBy 和 Shift 操作经常被用来处理季节性数据或计算同比增长率:

import pandas as pd
import numpy as np

# 创建示例数据
np.random.seed(0)
dates = pd.date_range(start='2020-01-01', end='2022-12-31', freq='D')
data = {
    'date': dates,
    'sales': np.random.randint(100, 1000, size=len(dates))
}
df = pd.DataFrame(data)

# 添加年份和月份列
df['year'] = df['date'].dt.year
df['month'] = df['date'].dt.month

# 计算同比增长率
df['yoy_growth'] = df.groupby('month')['sales'].pct_change(periods=12) * 100

print("Year-over-year growth from pandasdataframe.com:")
print(df.tail(10))

Output:

Pandas GroupBy 和 Shift 操作:高效数据分析的关键技巧

在这个例子中,我们首先创建了一个包含三年日销售数据的 DataFrame。然后,我们添加了年份和月份列,并使用 groupby('month')pct_change(periods=12) 来计算同比增长率。这个操作会比较每个月的销售额与去年同月的销售额,计算增长率。

4.2 金融数据分析

在金融数据分析中,GroupBy 和 Shift 操作可以用来计算各种技术指标,如移动平均线交叉策略:

import pandas as pd
import numpy as np

# 创建示例数据
np.random.seed(0)
dates = pd.date_range(start='2022-01-01', end='2022-12-31', freq='D')
data = {
    'date': dates,
    'price': np.cumsum(np.random.randn(len(dates))) + 100
}
df = pd.DataFrame(data)

# 计算短期和长期移动平均线
df['SMA5'] = df['price'].rolling(window=5).mean()
df['SMA20'] = df['price'].rolling(window=20).mean()

# 计算金叉和死叉信号
df['golden_cross'] = np.where((df['SMA5'] > df['SMA20']) & (df['SMA5'].shift(1) <= df['SMA20'].shift(1)), 1, 0)
df['death_cross'] = np.where((df['SMA5'] < df['SMA20']) & (df['SMA5'].shift(1) >= df['SMA20'].shift(1)), 1, 0)

print("Moving average crossover signals from pandasdataframe.com:")
print(df[df['golden_cross'] | df['death_cross']])

在这个例子中,我们首先创建了一个包含一年股价数据的 DataFrame。然后,我们计算了5天和20天的简单移动平均线(SMA)。接着,我们使用 shift() 操作来检测金叉(短期均线从下方穿过长期均线)和死叉(短期均线从上方穿过长期均线)信号。

4.3 客户行为分析

在客户行为分析中,GroupBy 和 Shift 操作可以用来计算客户的留存率或者分析购买模式:

import pandas as pd
import numpy as np

# 创建示例数据
np.random.seed(0)
data = {
    'customer_id': np.repeat(range(1, 101), 5),
    'date': np.sort(np.random.choice(pd.date_range(start='2022-01-01', end='2022-12-31'), size=500)),
    'purchase_amount': np.random.randint(10, 1000, size=500)
}
df = pd.DataFrame(data)

# 按客户和日期排序
df = df.sort_values(['customer_id', 'date'])

# 计算每个客户的购买间隔
df['days_since_last_purchase'] = df.groupby('customer_id')['date'].diff().dt.days

# 计算每个客户的累积购买金额
df['cumulative_purchase'] = df.groupby('customer_id')['purchase_amount'].cumsum()

print("Customer purchase analysis from pandasdataframe.com:")
print(df.head(10))

Output:

Pandas GroupBy 和 Shift 操作:高效数据分析的关键技巧

在这个例子中,我们创建了一个包含客户购买记录的 DataFrame。然后,我们使用 groupby('customer_id')diff() 来计算每个客户的购买间隔。我们还使用 cumsum() 来计算每个客户的累积购买金额。这种分析可以帮助我们了解客户的购买频率和消费模式。

5. 性能优化技巧

在处理大型数据集时,GroupBy 和 Shift 操作可能会变得很慢。以下是一些优化性能的技巧:

  1. 使用 categorical 数据类型:如果分组的列有有限的唯一值,将其转换为 categorical 类型可以显著提高性能。

  2. 使用 numba 加速:对于自定义的聚合函数,可以使用 numba 库来加速计算。

  3. 使用 swifter 库:swifter 库可以自动决定是否使用并行处理来加速 apply 操作。

  4. 预先排序:如果数据已经按照分组列排序,GroupBy 操作会更快。

  5. 使用 transform 而不是 apply:在可能的情况下,使用 transform 方法可能比 apply 更快。

  6. 考虑使用 SQL:对于非常大的数据集,使用 SQL 数据库可能比 Pandas 更有效率。

6. 常见陷阱和注意事项

在使用 GroupBy 和 Shift 操作时,有一些常见的陷阱需要注意:

  1. 数据类型不一致:确保分组列的数据类型一致,否则可能导致意外的结果。

  2. 处理缺失值:Shift 操作可能会引入 NaN 值,需要适当处理。

  3. 索引问题:GroupBy 操作后的结果可能会改变索引,需要注意对齐问题。

  4. 内存使用:大型数据集上的 GroupBy 操作可能会消耗大量内存,需要考虑使用迭代器或分块处理。

  5. 排序假设:某些操作(如 shift())假设数据已经正确排序,确保在必要时对数据进行排序。

结论

Pandas 的 GroupBy 和 Shift 操作是数据分析中非常强大的工具。它们允许我们进行复杂的分组计算、时间序列分析和滚动计算。通过本文的详细介绍和丰富的示例,我们展示了这些操作在各种场景下的应用,从基本的数据处理到高级的金融分析和客户行为研究。

掌握这些技术可以大大提高数据分析的效率和深度。然而,在处理大型数据集时,也需要注意性能优化和潜在的陷阱。通过持续练习和实践,你将能够更加熟练地运用这些工具,从而更好地挖掘数据中的洞察。

记住,数据分析是一个不断学习和探索的过程。随着你对 Pandas 的 GroupBy 和 Shift 操作越来越熟悉,你会发现更多创新的方式来应用这些工具,解决各种复杂的数据分析问题。继续探索,不断实践,你将成为一个更加全面和高效的数据分析师。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程