表格里面相同键的有多条记录,为什么有些只打印了第一条没有打印最后一条 import pandas as pd from pathlib import Path def extract_matching_pairs(main_excel, sample_csv, output_sheet="样本匹配结果"): try: # 1. 读取主Excel文件 with pd.ExcelFile(main_excel) as xls: df_main = pd.read_excel(xls, sheet_name=xls.sheet_names[1], converters={'card_num': str, 'card_batch': str}) print(f"已读取主文件工作表: {xls.sheet_names[1]}") # 2. 读取样本CSV文件 df_sample = pd.read_csv(sample_csv, dtype={'cardNum': str, 'cardBatch': str}) # 3. 数据清洗和键创建 def clean_key(s): """统一键格式:去除空格和.0后缀""" s = str(s).strip() return s[:-2] if s.endswith('.0') else s # 主文件键:card_num + card_batch df_main['匹配键'] = df_main['card_num'].apply(clean_key) + '|' + df_main['card_batch'].apply(clean_key) # 样本文件键:cardNum + cardBatch df_sample['匹配键'] = df_sample['cardNum'].apply(clean_key) + '|' + df_sample['cardBatch'].apply(clean_key) # 4. 找出两表共有的匹配键 common_keys = set(df_main['匹配键']).intersection(set(df_sample['匹配键'])) print(f"找到 {len(common_keys)} 组完全匹配的数据组合") # 5. 从样本文件中提取每组匹配的首尾记录 result_records = [] for key in common_keys: matched = df_sample[df_sample['匹配键'] == key] if not matched.empty: result_records.append(matched.iloc[0]) # 首条记录 if len(matched) > 1: result_records.append(matched.iloc[-1]) # 末条记录 # 6. 保存结果到主文件的新工作表 if result_records: result_df = pd.DataFrame(result_records).drop(columns=['匹配键']) with pd.ExcelWriter(main_excel, engine='openpyxl', mode='a') as writer: # 删除已存在的输出工作表 from openpyxl import load_workbook wb = load_workbook(main_excel) if output_sheet in wb.sheetnames: del wb[output_sheet] wb
时间: 2025-06-25 08:16:35 浏览: 11
<think>好的,我现在需要解决用户的问题:在使用pandas处理重复键时,为何某些情况下只打印了第一条而未显示最后一条,如何确保同时保留并打印首尾两条记录?
首先,用户提到的问题可能涉及到重复数据的处理。根据提供的引用内容,特别是引用[3]和[4],用户可能在使用duplicated()方法时遇到了问题。duplicated()默认标记的是重复项中的非首次出现,所以当用户筛选重复值时,可能只看到了后续的重复记录,而第一条没有被包含进去。例如,引用[3]中的代码使用df[df.duplicated(subset=['name']) == True]来打印重复的值,这样只会显示除了第一次出现之外的重复行,因此第一条记录不会被包含在结果中。
接下来,用户希望同时保留首条和最后一条记录。这可能需要结合duplicated()的参数调整以及分组操作。例如,修改duplicated()的keep参数,将其设置为False,这样所有的重复行都会被标记为True,但这样会包括所有重复项,而不仅仅是首尾。不过这可能不是用户需要的,因为用户可能希望针对每个重复组保留首尾两条。
另一个方法是使用groupby来分组,然后在每个分组中取第一条和最后一条记录。例如,对每个重复的键进行分组,然后应用head(1)和tail(1),再将结果合并。但需要注意,如何确定哪些键是重复的,这可能需要先筛选出有重复的键,再进行分组操作。
此外,引用[4]提到,duplicated()的参数ignore_index可能影响结果,但具体如何影响还需要查阅文档。不过更关键的是,用户需要同时获取每个重复组的首尾记录,这可能涉及到两次筛选:一次保留首次出现,另一次保留最后一次出现,然后将两者合并。
可能的解决步骤是:
1. 确定哪些键是重复的。例如,使用duplicated(keep=False)来标记所有重复行。
2. 筛选出这些重复的行,然后按重复的键分组。
3. 对每个分组取第一条和最后一条记录。
4. 合并这些记录,并去重,避免重复包含中间记录。
或者,可以使用两次duplicated,第一次标记首次出现以外的记录,第二次标记最后一次出现以外的记录,然后取反,再将这两个条件结合,得到所有首尾记录。
例如,对于每个重复的键,保留第一个和最后一个出现的位置。这可能需要对每个组应用索引操作,获取第一个和最后一个索引,然后通过iloc选择这些行。
此外,在合并时需要注意避免重复,尤其是当某个重复组只有两个记录时,首尾是同一个记录,此时需要确保只保留一次。
现在需要验证这些思路是否正确。例如,假设有一个DataFrame如下:
name age
0 A 20
1 A 25
2 B 30
3 A 28
4 B 35
其中,A出现了三次,B两次。用户希望对于每个重复的键(A和B),保留首尾记录,即A的0和3行,B的2和4行。
首先,找到所有重复的键:
df[df.duplicated(subset=['name'], keep=False)]
这将返回所有重复的name,包括所有A和B的行。
然后,对每个name分组,并应用函数来取第一个和最后一个:
df_grouped = df.groupby('name').filter(lambda x: len(x) > 1) # 这一步可能不需要,因为已经通过duplicated筛选了重复的键
然后,对每个分组取首尾:
result = df.groupby('name').apply(lambda x: x.iloc[[0, -1]]).reset_index(drop=True)
这将得到每个重复组的首尾记录。但需要确认是否正确。
但可能存在的问题是,如果某个组只有一个记录,会被排除,但通过之前的筛选,已经确保所有组都是重复的,所以没问题。
因此,用户的问题可以通过分组后取首尾来解决。但需要组合这些步骤,并确保正确筛选重复的键。
此外,用户可能在打印时没有正确处理这些记录,比如只筛选了重复的非首行,而没有同时获取首行。因此,解决方案需要确保同时获取首尾。
最后,结合引用中的内容,特别是引用[3]中的例子,用户可能在使用duplicated时仅检查后续重复项,而忽略了首项。因此,调整duplicated的参数或者采用分组方法可以解决该问题。</think>在处理Pandas重复键时,若需同时保留并打印首条与最后一条记录,需理解`duplicated()`的机制并调整筛选逻辑。以下是具体解决方案:
---
### 一、问题原因分析
当使用`df[df.duplicated(subset=['key'])]`时,默认行为是标记**非首次出现**的重复行(`keep='first'`),因此首条记录会被过滤掉[^3]。若需保留首尾两条记录,需通过以下方法调整。
---
### 二、解决方案步骤
#### 1. 标记所有重复行
使用`duplicated(keep=False)`标记所有重复行(包括首尾):
```python
mask = df.duplicated(subset=['key'], keep=False)
duplicates = df[mask]
```
#### 2. 按重复键分组并提取首尾记录
通过分组操作获取每个重复组的首尾行:
```python
result = duplicates.groupby('key').apply(lambda x: x.iloc[[0, -1]]).reset_index(drop=True)
```
#### 3. 合并结果并去重(若需要)
若需完全独立的记录(如首尾相同则保留一条):
```python
result = result.drop_duplicates()
```
---
### 三、完整代码示例
```python
import pandas as pd
# 示例数据
data = {'key': ['A', 'A', 'B', 'A', 'B'], 'value': [10, 20, 30, 40, 50]}
df = pd.DataFrame(data)
# 标记所有重复行
mask = df.duplicated('key', keep=False)
duplicates = df[mask]
# 按key分组提取首尾记录
result = duplicates.groupby('key').apply(lambda x: x.iloc[[0, -1]]).reset_index(drop=True)
print("原始数据:\n", df)
print("\n首尾记录:\n", result)
```
输出结果:
```
原始数据:
key value
0 A 10
1 A 20
2 B 30
3 A 40
4 B 50
首尾记录:
key value
0 A 10
1 A 40
2 B 30
3 B 50
```
---
### 四、关键点解释
1. **`keep=False`参数**:标记所有重复行(包括首尾),而非仅后续重复项[^4]。
2. **分组提取逻辑**:通过`groupby`按重复键分组,再通过`iloc[[0, -1]]`获取每组首尾行。
3. **去重处理**:若首尾行相同(如单行重复),需额外使用`drop_duplicates()`。
---
阅读全文
相关推荐





