
在数据分析中,我们经常需要识别数据集中不同元素之间的关联模式。例如,在一个包含“分类”和“个体”信息的dataframe中,我们可能需要找出在每个特定“分类”下,“个体”之间形成的无序组合(如对或三元组)出现的频率。这里的“无序”意味着组合 (a, b) 与 (b, a) 被视为同一个。最终目标是不仅统计这些组合的出现次数,还要计算它们在该分类下相对于最大出现次数的百分比。
假设我们有如下DataFrame:
import pandas as pd
data = {
'Classification': [1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5],
'Individual': ['A', 'A', 'B', 'B', 'A', 'A', 'B', 'C', 'C', 'C', 'A', 'A', 'A', 'B', 'B', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'C', 'C', 'C', 'A', 'A', 'B', 'B', 'B']
}
df = pd.DataFrame(data)
print(df.head())我们希望得到的结果是针对每个Classification,列出其中出现的Individual的无序对和三元组,并统计它们的出现次数及相对百分比。
为了解决这个问题,我们将主要利用Python的itertools模块和Pandas库的强大功能。
整个处理流程可以分为以下几个关键步骤:
首先,我们需要一个函数来为每个分类下的个体生成所有长度为2及以上的无序组合。
from itertools import chain, combinations
def generate_combinations(elements):
"""
生成给定元素集合的所有长度 >= 2 的无序组合。
先将元素转换为集合以确保唯一性,然后生成组合。
"""
unique_elements = set(elements)
# 从长度2到元素总数,生成所有组合
return list(chain.from_iterable(combinations(unique_elements, r)
for r in range(2, len(unique_elements) + 1)))
这个generate_combinations函数接收一个列表(例如,某个Classification下的所有Individual),首先将其转换为set以去除重复的个体(例如,['A', 'A', 'B']会变为{'A', 'B'}),然后使用itertools.combinations生成所有可能的对、三元组等组合。chain.from_iterable用于将不同长度的组合列表展平为一个列表。
接下来,我们按Classification列对DataFrame进行分组,对每个组内的Individual列应用我们定义的generate_combinations函数,然后使用explode将生成的组合列表展开。
# 步骤1: 按 'Classification' 分组,对 'Individual' 应用组合生成函数
# 结果 'out_combinations' 的 'ValueSeries' 列将包含元组形式的组合
out_combinations = df.groupby('Classification')['Individual'].agg(generate_combinations).explode()
# 查看中间结果
print("\n--- 分组、生成组合并展开后的结果 (部分) ---")
print(out_combinations.head(10))out_combinations现在是一个Series,其索引是Classification,值是各种组合(以元组形式)。
我们需要统计每种组合(无论属于哪个Classification)在整个out_combinations Series中出现的总次数。
# 步骤2: 计算每种组合的总出现次数
# 这里使用 value_counts() 统计所有组合的频率
combination_counts = out_combinations.value_counts().rename('TimesClassification')
# 查看组合计数结果
print("\n--- 组合总出现次数 (部分) ---")
print(combination_counts.head())combination_counts是一个Series,索引是组合元组,值是它们的总出现次数。
最后一步是将组合的出现次数合并回我们的主结果DataFrame,并计算PercentageClassification。
# 步骤3: 将组合计数合并回原始分组结果
# reset_index() 将索引 'Classification' 和 Series 值 'ValueSeries' 转换为列
result_df = (out_combinations
.reset_index(name='ValueSeries')
.merge(combination_counts,
how='left',
left_on='ValueSeries',
right_index=True))
# 步骤4: 计算 PercentageClassification
# 对于每个 Classification 组,计算其内部 TimesClassification 的最大值,然后用 TimesClassification 除以这个最大值
result_df = result_df.assign(
PercentageClassification=lambda d: d['TimesClassification'] / d.groupby('Classification')['TimesClassification'].transform('max')
)
# 最终结果排序以便查看
result_df = result_df.sort_values(by=['Classification', 'ValueSeries']).reset_index(drop=True)
print("\n--- 最终结果 ---")
print(result_df)将以上步骤整合,得到完整的解决方案代码:
import pandas as pd
from itertools import chain, combinations
# 示例数据
data = {
'Classification': [1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5],
'Individual': ['A', 'A', 'B', 'B', 'A', 'A', 'B', 'C', 'C', 'C', 'A', 'A', 'A', 'B', 'B', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'C', 'C', 'C', 'A', 'A', 'B', 'B', 'B']
}
df = pd.DataFrame(data)
def generate_combinations(elements):
"""
生成给定元素集合的所有长度 >= 2 的无序组合。
先将元素转换为集合以确保唯一性,然后生成组合。
"""
unique_elements = set(elements)
return list(chain.from_iterable(combinations(unique_elements, r)
for r in range(2, len(unique_elements) + 1)))
# 1. 按 'Classification' 分组,对 'Individual' 应用组合生成函数,并展开
out_combinations = df.groupby('Classification')['Individual'].agg(generate_combinations).explode()
# 2. 计算每种组合的总出现次数
combination_counts = out_combinations.value_counts().rename('TimesClassification')
# 3. 将组合计数合并回原始分组结果
result_df = (out_combinations
.reset_index(name='ValueSeries')
.merge(combination_counts,
how='left',
left_on='ValueSeries',
right_index=True))
# 4. 计算 PercentageClassification
result_df = result_df.assign(
PercentageClassification=lambda d: d['TimesClassification'] / d.groupby('Classification')['TimesClassification'].transform('max')
)
# 排序并重置索引以便输出美观
result_df = result_df.sort_values(by=['Classification', 'ValueSeries']).reset_index(drop=True)
print(result_df)输出结果:
Classification ValueSeries TimesClassification PercentageClassification 0 1 (A, B) 5 1.0 1 2 (A, B) 5 1.0 2 3 (A, B) 5 1.0 3 3 (A, C) 3 0.6 4 3 (A, B, C) 3 0.6 5 3 (B, C) 3 0.6 6 4 (A, B) 5 1.0 7 4 (A, C) 3 0.6 8 4 (A, B, C) 3 0.6 9 4 (B, C) 3 0.6 10 5 (A, B) 5 1.0 11 5 (A, C) 3 0.6 12 5 (A, B, C) 3 0.6 13 5 (B, C) 3 0.6
请注意,示例输出中 (C, A) 和 (A, C) 等价。itertools.combinations 生成的组合内部元素顺序是根据输入元素的顺序确定的,但作为集合的组合,它们是无序的。在实际应用中,如果需要规范化表示(例如总是按字母顺序),可以对元组内的元素进行排序后再进行统计,但对于本例而言,当前的元组形式已经足够表示无序组合。
本文详细阐述了如何利用Pandas和itertools库在DataFrame中高效地统计指定列的无序组合(如对和三元组)。通过将数据分组、生成组合、展开、计数并最终合并计算百分比,我们能够深入挖掘数据中隐藏的关联模式。这种方法不仅灵活,可以根据需求调整组合的长度,而且在处理中等规模数据集时表现出色,为数据分析师提供了一个强大的工具。
以上就是Pandas DataFrame中无序组合(对与三元组)的统计与分析的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号