趋近智
重复记录,即在所有或部分列中包含完全相同信息的行,会明显扭曲分析结果和模型表现。它们可能使计数虚高,使统计摘要(如均值或频率)产生偏差,并可能导致合作方得出错误结论。识别并妥善处理这些重复项是加载数据并进行初步检查后的重要一步。
Pandas提供了一个简单直接的方法,duplicated(),用于识别DataFrame中的重复行。默认情况下,此方法会检查整行是否是DataFrame中之前出现过的行的精确副本。它返回一个布尔Series,其中True表示该行是前面某行的重复项。
我们来看一个简单的DataFrame:
import pandas as pd
data = {'col_a': ['apple', 'banana', 'orange', 'apple', 'banana', 'grape'],
'col_b': [1, 2, 3, 1, 2, 4],
'col_c': [True, False, True, True, False, False]}
df_duplicates = pd.DataFrame(data)
print("原始DataFrame:")
print(df_duplicates)
# 识别重复行(基于所有列)
duplicate_mask = df_duplicates.duplicated()
print("\n重复项的布尔掩码:")
print(duplicate_mask)
这段代码将输出:
Original DataFrame:
col_a col_b col_c
0 apple 1 True
1 banana 2 False
2 orange 3 True
3 apple 1 True
4 banana 2 False
5 grape 4 False
Boolean mask for duplicates:
0 False
1 False
2 False
3 True
4 True
5 False
dtype: bool
正如你所见,第3行和第4行被标记为True,因为它们分别是第0行和第1行的精确重复项。
要获取重复行的计数,你可以简单地对布尔Series求和:
num_duplicates = df_duplicates.duplicated().sum()
print(f"\n找到的重复行数量: {num_duplicates}")
# 输出: 找到的重复行数量: 2
要查看实际的重复行,你可以使用布尔索引:
print("\n重复行:")
print(df_duplicates[df_duplicates.duplicated()])
Duplicate rows:
col_a col_b col_c
3 apple 1 True
4 banana 2 False
有时,重复项的定义并非基于整行匹配,而是基于特定列子集具有相同值。例如,如果两条记录共享相同的用户ID和时间戳,即使其他列略有不同(可能是由于数据录入差异),你也可以认为它们是重复项。你可以使用subset参数指定要考虑的列:
# 仅基于'col_a'和'col_b'检查重复项
subset_duplicates = df_duplicates.duplicated(subset=['col_a', 'col_b'])
print("\n基于'col_a'和'col_b'的重复项:")
print(subset_duplicates)
print("\n基于子集识别为重复项的DataFrame行:")
print(df_duplicates[subset_duplicates])
Duplicates based on 'col_a' and 'col_b':
0 False
1 False
2 False
3 True
4 True
5 False
dtype: bool
DataFrame rows identified as duplicates based on subset:
col_a col_b col_c
3 apple 1 True
4 banana 2 False
在这个例子中,结果与检查所有列时相同,因为这些重复项无论如何都匹配了所有列。但是,如果第3行的col_c是False,在使用subset=['col_a', 'col_b']时,它仍然会被标记为重复项。
一旦识别出来,处理重复行最常用的方法是将其移除。Pandas为此提供了drop_duplicates()方法。与duplicated()类似,它默认作用于整行,也可以限定到列的subset。
一个重要的参数用于drop_duplicates()是keep,用于决定保留哪个重复行:
keep='first': (默认)保留重复行的第一次出现,移除后续的。keep='last': 保留重复行的最后一次出现,移除前面的。keep=False: 移除所有作为重复项的行。如果一行出现两次,则这两个实例都会被移除。我们来看看这是如何运作的:
# 移除重复项,保留第一次出现(默认)
df_no_duplicates_first = df_duplicates.drop_duplicates()
print("\n移除重复项后(保留第一次)的DataFrame:")
print(df_no_duplicates_first)
# 移除重复项,保留最后一次出现
df_no_duplicates_last = df_duplicates.drop_duplicates(keep='last')
print("\n移除重复项后(保留最后一次)的DataFrame:")
print(df_no_duplicates_last)
# 移除重复项,删除所有重复实例
df_no_duplicates_all = df_duplicates.drop_duplicates(keep=False)
print("\n移除重复项后(不保留任何)的DataFrame:")
print(df_no_duplicates_all)
# 基于子集移除重复项,保留第一次出现
df_no_duplicates_subset = df_duplicates.drop_duplicates(subset=['col_a', 'col_b'], keep='first')
print("\n基于子集移除重复项后(保留第一次)的DataFrame:")
print(df_no_duplicates_subset)
输出展示了不同的行为:
DataFrame after dropping duplicates (keeping first):
col_a col_b col_c
0 apple 1 True
1 banana 2 False
2 orange 3 True
5 grape 4 False
DataFrame after dropping duplicates (keeping last):
col_a col_b col_c
2 orange 3 True
3 apple 1 True
4 banana 2 False
5 grape 4 False
DataFrame after dropping duplicates (keeping none):
col_a col_b col_c
2 orange 3 True
5 grape 4 False
DataFrame after dropping duplicates based on subset (keeping first):
col_a col_b col_c
0 apple 1 True
1 banana 2 False
2 orange 3 True
5 grape 4 False
请注意,keep='first'保留了第0、1、2、5行;keep='last'保留了第2、3、4、5行;而keep=False仅保留了第2和第5行,因为它们是原始DataFrame中唯一的行。在这种特定情况下,基于子集['col_a', 'col_b']移除重复项并使用keep='first'与默认的drop_duplicates()结果相同。
默认情况下,drop_duplicates()返回一个移除了重复项的新DataFrame。原始DataFrame保持不变。如果你想直接修改DataFrame,可以使用inplace=True参数,尽管通常将结果赋值给新变量或覆盖现有变量(如df = df.drop_duplicates())更安全、更清晰。
处理重复项是数据清洗中的标准流程。决定是检查所有列还是子集,以及决定保留哪个重复项(如果有的话),在很大程度上取决于你的数据背景和分析目标。在决定移除策略之前,务必考虑重复可能出现的原因(例如,数据录入错误、系统日志问题、有意重复)。
这部分内容有帮助吗?
duplicated() 方法的官方文档,解释了其用于识别重复行的用法。drop_duplicates() 方法的官方文档,详细说明了其删除重复行的参数。© 2026 ApX Machine Learning用心打造