对比学习法增改

This commit is contained in:
2025-10-29 11:39:30 +08:00
parent 1f8667ae51
commit 95d719cc1e
5 changed files with 466 additions and 0 deletions

151
contrast learning/copy.py Normal file
View File

@@ -0,0 +1,151 @@
import shutil
from pathlib import Path
def find_element_column_index(cif_lines: list) -> int:
"""
在CIF文件内容中查找 _atom_site_type_symbol 所在的列索引。
:param cif_lines: 从CIF文件读取的行列表。
:return: 元素符号列的索引从0开始如果未找到则返回-1。
"""
in_loop_header = False
column_index = -1
current_column = 0
for line in cif_lines:
line_stripped = line.strip()
if not line_stripped:
continue
if line_stripped.startswith('loop_'):
in_loop_header = True
column_index = -1
current_column = 0
continue
if in_loop_header:
if line_stripped.startswith('_'):
if line_stripped.startswith('_atom_site_type_symbol'):
column_index = current_column
current_column += 1
else:
# loop_ 头部定义结束,开始数据行
return column_index
return -1 # 如果文件中没有找到 loop_ 或 _atom_site_type_symbol
def copy_cif_with_O_or_S_robust(source_dir: str, target_dir: str, dry_run: bool = False):
"""
从源文件夹中筛选出内容包含'O''S'元素的CIF文件并复制到目标文件夹。
(鲁棒版能正确解析CIF中的元素符号列)
:param source_dir: 源文件夹路径包含CIF文件。
:param target_dir: 目标文件夹路径,用于存放筛选出的文件。
:param dry_run: 如果为True则只打印将要复制的文件而不实际执行复制操作。
"""
# 1. 路径处理和验证
source_path = Path(source_dir)
target_path = Path(target_dir)
if not source_path.is_dir():
print(f"错误:源文件夹 '{source_dir}' 不存在或不是一个文件夹。")
return
if not dry_run and not target_path.exists():
target_path.mkdir(parents=True, exist_ok=True)
print(f"目标文件夹 '{target_dir}' 已创建。")
print(f"源文件夹: {source_path}")
print(f"目标文件夹: {target_path}")
if dry_run:
print("\n--- *** 模拟运行模式 (Dry Run) *** ---")
print("--- 不会执行任何实际的文件复制操作 ---")
# 2. 开始遍历和筛选
print("\n开始扫描源文件夹中的CIF文件...")
copied_count = 0
checked_files = 0
error_files = 0
# 使用 rglob('*.cif') 可以遍历所有子文件夹,如果只想遍历当前文件夹用 glob
for file_path in source_path.glob('*.cif'):
if file_path.is_file():
checked_files += 1
try:
with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
lines = f.readlines()
# 步骤 A: 找到元素符号在哪一列
element_col_idx = find_element_column_index(lines)
if element_col_idx == -1:
# 在某些CIF文件中可能没有loop块而是简单的 key-value 格式
# 为了兼容这种情况,我们保留一个简化的检查
found_simple = any(
line.strip().startswith(('_chemical_formula_sum', '_chemical_formula_structural')) and (
' O' in line or ' S' in line) for line in lines)
if not found_simple:
continue # 如果两种方法都找不到,跳过此文件
# 步骤 B: 检查该列是否有 'O' 或 'S'
found = False
for line in lines:
line_stripped = line.strip()
# 忽略空行、注释行和定义行
if not line_stripped or line_stripped.startswith(('#', '_', 'loop_')):
continue
parts = line_stripped.split()
# 确保行中有足够的列
if len(parts) > element_col_idx:
# 元素符号可能带有电荷,如 O2-,所以用 startswith
atom_symbol = parts[element_col_idx].strip()
if atom_symbol == 'O' or atom_symbol == 'S':
found = True
break
# 兼容性检查:如果通过了 found_simple 的检查,也标记为找到
if found_simple:
found = True
if found:
target_file_path = target_path / file_path.name
print(f"找到匹配: '{file_path.name}' (含有 O 或 S 元素)")
if not dry_run:
shutil.copy2(file_path, target_file_path)
# print(f" -> 已复制到 {target_file_path}") # 可以取消注释以获得更详细的输出
copied_count += 1
except Exception as e:
error_files += 1
print(f"!! 处理文件 '{file_path.name}' 时发生错误: {e}")
# 3. 打印最终报告
print("\n--- 操作总结 ---")
print(f"共检查了 {checked_files} 个.cif文件。")
if error_files > 0:
print(f"处理过程中有 {error_files} 个文件发生错误。")
if dry_run:
print(f"模拟运行结束:如果实际运行,将会有 {copied_count} 个文件被复制。")
else:
print(f"成功复制了 {copied_count} 个文件到目标文件夹。")
if __name__ == '__main__':
# !! 重要:请将下面的路径修改为您自己电脑上的实际路径
source_folder = "D:/download/2025-10/data_all/input/input"
target_folder = "D:/download/2025-10/data_all/output"
# --- 第一次运行:使用模拟模式 (Dry Run) ---
print("================ 第一次运行: 模拟模式 ================")
copy_cif_with_O_or_S_robust(source_folder, target_folder, dry_run=True)
print("\n\n=======================================================")
input("检查上面的模拟运行结果。如果符合预期,按回车键继续执行实际复制操作...")
print("=======================================================")
# --- 第二次运行:实际执行复制 ---
print("\n================ 第二次运行: 实际复制模式 ================")
copy_cif_with_O_or_S_robust(source_folder, target_folder, dry_run=False)

111
contrast learning/delete.py Normal file
View File

@@ -0,0 +1,111 @@
import shutil
from pathlib import Path
def delete_duplicates_from_second_folder(source_dir: str, target_dir: str, dry_run: bool = False):
"""
删除第二个文件夹中与第一个文件夹内项目同名的文件或文件夹。
:param source_dir: 第一个文件夹(源)的路径。
:param target_dir: 第二个文件夹(目标)的路径,将从此文件夹中删除内容。
:param dry_run: 如果为True则只打印将要删除的内容而不实际执行删除操作。
"""
# 1. 将字符串路径转换为Path对象方便操作
source_path = Path(source_dir)
target_path = Path(target_dir)
# 2. 验证路径是否存在且为文件夹
if not source_path.is_dir():
print(f"错误:源文件夹 '{source_dir}' 不存在或不是一个文件夹。")
return
if not target_path.is_dir():
print(f"错误:目标文件夹 '{target_dir}' 不存在或不是一个文件夹。")
return
print(f"源文件夹: {source_path}")
print(f"目标文件夹: {target_path}")
if dry_run:
print("\n--- *** 模拟运行模式 (Dry Run) *** ---")
print("--- 不会执行任何实际的删除操作 ---")
# 3. 获取源文件夹中所有项目(文件和子文件夹)的名称
# p.name 会返回路径的最后一部分,即文件名或文件夹名
source_item_names = {p.name for p in source_path.iterdir()}
if not source_item_names:
print("\n源文件夹为空,无需执行任何操作。")
return
print(f"\n在源文件夹中找到 {len(source_item_names)} 个项目。")
print("开始检查并删除目标文件夹中的同名项目...")
deleted_count = 0
# 4. 遍历源文件夹中的项目名称
for item_name in source_item_names:
# 构建目标文件夹中可能存在的同名项目的完整路径
item_to_delete = target_path / item_name
# 5. 检查该项目是否存在于目标文件夹中
if item_to_delete.exists():
try:
if item_to_delete.is_file():
# 如果是文件,直接删除
print(f"准备删除文件: {item_to_delete}")
if not dry_run:
item_to_delete.unlink()
print(" -> 已删除。")
deleted_count += 1
elif item_to_delete.is_dir():
# 如果是文件夹,使用 shutil.rmtree 删除整个文件夹及其内容
print(f"准备删除文件夹及其所有内容: {item_to_delete}")
if not dry_run:
shutil.rmtree(item_to_delete)
print(" -> 已删除。")
deleted_count += 1
except Exception as e:
print(f"!! 删除 '{item_to_delete}' 时发生错误: {e}")
if deleted_count == 0:
print("\n操作完成:在目标文件夹中没有找到需要删除的同名项目。")
else:
if dry_run:
print(f"\n模拟运行结束:如果实际运行,将会有 {deleted_count} 个项目被删除。")
else:
print(f"\n操作完成:总共删除了 {deleted_count} 个项目。")
# --- 使用示例 ---
# 在运行前,请创建以下文件夹和文件结构进行测试:
# /your/path/folder1/
# ├── file_a.txt
# ├── file_b.log
# └── subfolder_x/
# └── test.txt
# /your/path/folder2/
# ├── file_a.txt (将被删除)
# ├── file_c.md
# └── subfolder_x/ (将被删除)
# └── another.txt
if __name__ == '__main__':
# !! 重要:请将下面的路径修改为您自己电脑上的实际路径
folder1_path = "D:/download/2025-10/after_step5/after_step5/S" # 源文件夹
folder2_path = "D:/download/2025-10/input/input" # 目标文件夹
# --- 第一次运行:使用模拟模式 (Dry Run),非常推荐!---
# 这会告诉你脚本将要做什么,但不会真的删除任何东西。
print("================ 第一次运行: 模拟模式 ================")
delete_duplicates_from_second_folder(folder1_path, folder2_path, dry_run=True)
print("\n\n=======================================================")
input("检查上面的模拟运行结果。如果符合预期,按回车键继续执行实际删除操作...")
print("=======================================================")
# --- 第二次运行:实际执行删除 ---
# 确认模拟运行结果无误后,再将 dry_run 设置为 False 或移除该参数。
print("\n================ 第二次运行: 实际删除模式 ================")
delete_duplicates_from_second_folder(folder1_path, folder2_path, dry_run=False)