以下是一个重构后的高可用、可配置、低耦合的专利CSV处理函数,包含清晰的注释和结构:

import csv
import pandas as pd
from datetime import datetime
import os
from typing import List, Dict, Any, Optional, Tuple
import logging# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)class PatentProcessor:"""专利数据处理器"""def __init__(self, config: Optional[Dict[str, Any]] = None):"""初始化专利处理器Args:config: 配置字典,包含处理选项"""self.config = config or self.get_default_config()@staticmethoddef get_default_config() -> Dict[str, Any]:"""获取默认配置"""return {'required_columns': ['id', 'inventor/author', 'title', 'priority date'],'author_column': 'inventor/author','split_separator': ',','filter_condition': None,  # 例如: {'column': 'assignee', 'value': '百度', 'case_sensitive': False}'output_columns': ['author', 'value', 'id', 'title_list', 'priority_date_list', 'start_year', 'end_year'],'encoding': 'utf-8'}def load_csv_data(self, csv_filepath: str) -> Optional[pd.DataFrame]:"""加载CSV文件数据Args:csv_filepath: CSV文件路径Returns:pandas DataFrame 或 None(如果加载失败)"""try:data = []with open(csv_filepath, encoding=self.config['encoding']) as f:reader = csv.reader(f)for row in reader:data.append(row)if len(data) < 2:logger.warning(f"File {csv_filepath} has insufficient data rows")return None# 使用第二行作为列名,第三行开始作为数据df = pd.DataFrame(data[2:], columns=data[1])logger.info(f"Successfully loaded CSV file: {csv_filepath}")return dfexcept FileNotFoundError:logger.error(f"Error: The file {csv_filepath} does not exist.")except Exception as e:logger.error(f"An unexpected error occurred while loading {csv_filepath}: {e}")return Nonedef apply_filters(self, df: pd.DataFrame) -> pd.DataFrame:"""应用数据过滤条件Args:df: 输入DataFrameReturns:过滤后的DataFrame"""filter_condition = self.config.get('filter_condition')if filter_condition:column = filter_condition['column']value = filter_condition['value']case_sensitive = filter_condition.get('case_sensitive', False)if column in df.columns:if case_sensitive:df = df[df[column].str.contains(value, na=False)]else:df = df[df[column].str.contains(value, case=False, na=False)]logger.info(f"Applied filter: {filter_condition}")return dfdef convert_to_excel(self, df: pd.DataFrame, csv_filepath: str) -> str:"""将DataFrame转换为Excel文件Args:df: 输入DataFramecsv_filepath: 原始CSV文件路径(用于生成输出路径)Returns:生成的Excel文件路径"""try:excel_filepath = csv_filepath.replace('.csv', '.xlsx')df.to_excel(excel_filepath, index=False)logger.info(f"CSV file has been converted to Excel: {excel_filepath}")return excel_filepathexcept Exception as e:logger.error(f"Error converting to Excel: {e}")return ""def process_authors(self, df: pd.DataFrame) -> pd.DataFrame:"""处理作者数据,进行统计和分析Args:df: 包含专利数据的DataFrameReturns:作者统计DataFrame"""# 选择需要的列required_cols = self.config['required_columns']missing_cols = [col for col in required_cols if col not in df.columns]if missing_cols:logger.warning(f"Missing columns: {missing_cols}. Available columns: {list(df.columns)}")required_cols = [col for col in required_cols if col in df.columns]df = df[required_cols].copy()# 分割作者列author_col = self.config['author_column']if author_col in df.columns:df[author_col] = df[author_col].str.split(self.config['split_separator'])df = df.explode(author_col)df[author_col] = df[author_col].str.strip()# 统计作者出现次数author_counts = df[author_col].value_counts()new_df = pd.DataFrame({'author': author_counts.index,'value': author_counts.values})# 修复:使用列表推导式而不是直接赋值new_df['id'] = [df[df[author_col] == author]['id'].tolist() for author in new_df['author']]new_df['title_list'] = [df[df[author_col] == author]['title'].tolist() for author in new_df['author']]if 'priority date' in df.columns:new_df['priority_date_list'] = [df[df[author_col] == author]['priority date'].tolist() for author in new_df['author']]# 计算开始和结束年份date_ranges = [self.calculate_date_range(dates) for dates in new_df['priority_date_list']]new_df['start_year'] = [start for start, _ in date_ranges]new_df['end_year'] = [end for _, end in date_ranges]return new_df@staticmethoddef calculate_date_range(date_list: List[str]) -> Tuple[Optional[int], Optional[int]]:"""计算日期列表的开始和结束年份Args:date_list: 日期字符串列表Returns:(开始年份, 结束年份) 元组"""valid_dates = []for date_str in date_list:if pd.notna(date_str) and date_str.strip():try:# 尝试多种日期格式date_obj = datetime.strptime(date_str.strip(), '%Y-%m-%d')valid_dates.append(date_obj)except ValueError:try:date_obj = datetime.strptime(date_str.strip(), '%Y/%m/%d')valid_dates.append(date_obj)except ValueError:# 如果无法解析日期,跳过continueif not valid_dates:return None, Nonemin_date = min(valid_dates)max_date = max(valid_dates)return min_date.year, max_date.yeardef save_author_stats(self, author_df: pd.DataFrame, csv_filepath: str) -> str:"""保存作者统计结果Args:author_df: 作者统计DataFramecsv_filepath: 原始CSV文件路径(用于生成输出路径)Returns:生成的统计文件路径"""try:rank_excel_filepath = csv_filepath.replace('.csv', '_rank.xlsx')# 只保存配置中指定的列output_cols = [col for col in self.config['output_columns'] if col in author_df.columns]author_df[output_cols].to_excel(rank_excel_filepath, index=False)logger.info(f"Author statistics saved: {rank_excel_filepath}")return rank_excel_filepathexcept Exception as e:logger.error(f"Error saving author statistics: {e}")return ""def process_patent_file(self, csv_filepath: str) -> Dict[str, str]:"""处理单个专利CSV文件Args:csv_filepath: CSV文件路径Returns:包含输出文件路径的字典"""results = {'original_file': csv_filepath}# 1. 加载数据df = self.load_csv_data(csv_filepath)if df is None or df.empty:return results# 2. 应用过滤条件df = self.apply_filters(df)# 3. 转换为Excelexcel_path = self.convert_to_excel(df, csv_filepath)results['excel_file'] = excel_path# 4. 处理作者数据author_df = self.process_authors(df)# 5. 保存作者统计stats_path = self.save_author_stats(author_df, csv_filepath)results['stats_file'] = stats_pathreturn results# 使用示例
def process_patents_folder(folder_path: str, file_list: List[str], config: Optional[Dict[str, Any]] = None):"""处理文件夹中的多个专利CSV文件Args:folder_path: 文件夹路径file_list: 要处理的文件列表config: 处理配置"""processor = PatentProcessor(config)for filename in file_list:file_path = os.path.join(folder_path, filename)logger.info(f"Processing file: {filename}")try:results = processor.process_patent_file(file_path)logger.info(f"Completed processing: {filename}")logger.info(f"Results: {results}")except Exception as e:logger.error(f"Error processing {filename}: {e}")# 配置示例
CUSTOM_CONFIG = {'required_columns': ['id', 'inventor/author', 'title', 'priority date'],'author_column': 'inventor/author','split_separator': ',','filter_condition': None,  # 例如: {'column': 'assignee', 'value': 'Google', 'case_sensitive': False}'output_columns': ['author', 'value', 'id', 'title_list', 'priority_date_list', 'start_year', 'end_year'],'encoding': 'utf-8'}if __name__ == "__main__":# 使用示例folder = r'E:files\patents'gp_files = ["gp-search-google.csv",]# 使用默认配置处理文件process_patents_folder(folder, gp_files)# 使用自定义配置处理文件# process_patents_folder(folder, gp_files, CUSTOM_CONFIG)

这个重构版本具有以下优点:

  1. 模块化设计:将功能拆分为多个独立的方法,每个方法只负责一个明确的任务
  2. 可配置性:通过配置字典可以灵活调整处理参数
  3. 错误处理:完善的异常处理和日志记录
  4. 类型提示:添加了类型提示,提高代码可读性和可维护性
  5. 灵活性:支持自定义过滤条件、输出列等
  6. 可扩展性:易于添加新的处理功能或修改现有逻辑
  7. 清晰的文档:每个方法都有详细的文档字符串说明参数和返回值

使用方法:

# 简单使用
processor = PatentProcessor()
results = processor.process_patent_file('path/to/patents.csv')# 自定义配置使用
config = {'filter_condition': {'column': 'assignee', 'value': 'Google', 'case_sensitive': False},'required_columns': ['id', 'inventor/author', 'title', 'priority date']
}
processor = PatentProcessor(config)
results = processor.process_patent_file('path/to/patents.csv')

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/919741.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/919741.shtml
英文地址,请注明出处:http://en.pswp.cn/news/919741.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

3-2〔OSCP ◈ 研记〕❘ WEB应用攻击▸WEB安全防护体系

郑重声明&#xff1a; 本文所有安全知识与技术&#xff0c;仅用于探讨、研究及学习&#xff0c;严禁用于违反国家法律法规的非法活动。对于因不当使用相关内容造成的任何损失或法律责任&#xff0c;本人不承担任何责任。 如需转载&#xff0c;请注明出处且不得用于商业盈利。 …

PCIe 5.0相比顶级PCIe 4.0有何提升?

还在为PCIe 4.0固态硬盘那7000MB/s的速度沾沾自喜&#xff1f;醒醒&#xff0c;朋友。当很多人还在讨论PCIe 4.0是否“性能过剩”时&#xff0c;真正面向未来的PCIe 5.0已经带着碾压级的实力&#xff0c;来到了我们面前。这不是一次常规的“升级”&#xff0c;更不是英特尔式的…

23种设计模式——适配器模式(Adapter)​详解

✅作者简介&#xff1a;大家好&#xff0c;我是 Meteors., 向往着更加简洁高效的代码写法与编程方式&#xff0c;持续分享Java技术内容。 &#x1f34e;个人主页&#xff1a;Meteors.的博客 &#x1f49e;当前专栏&#xff1a; 设计模式 ✨特色专栏&#xff1a; 知识分享 &…

Vue3源码reactivity响应式篇之Reactive

概览 vue3中reactive用于将普通对象转换为响应式对象&#xff0c;它的实现原理是通过Proxy和Reflect来实现的。具体的实现文件参见packages\reactivity\src\reactive.ts。本文会介绍reactive的相关api如下&#xff1a; reactive&#xff1a;将普通对象转换为响应式对象readonly…

初识数据结构——Map和Set:哈希表与二叉搜索树的魔法对决

数据结构专栏 ⬅(click) 大家好&#xff01;我是你们的老朋友——想不明白的过度思考者&#xff01;今天我们要一起探索Java中两个神奇的数据结构&#xff1a;Map和Set&#xff01;准备好了吗&#xff1f;让我们开始这场魔法之旅吧&#xff01;&#x1f3a9; &#x1f3af; 先…

Unreal Engine UStaticMeshComponent

UnrealUnreal Engine - UStaticMeshComponent&#x1f3db; 定义&#x1f3db; 类继承⚡ 关键特性⚙️ 常见配置&#x1f6e0;️ 使用方法&#x1f4da; 在 C 中使用&#x1f4da; 在蓝图中使用&#x1f3ae; 典型应用场景&#x1f4da; 常见子类与用途&#x1f4dd; 小结Unrea…

demo 汽车之家(渲染-筛选-排序-模块抽离数据)

效果图展示&#xff1a;代码截图注释详情实现笔记总体目标&#xff08;按需求点对照代码&#xff09;数据模块化、整体渲染框架、筛选/排序的高亮与行为&#xff0c;全部已在 Index.ets CarData.ets 落地。下面按图片需求 2~4 点逐条总结&#xff0c;并给出关键代码定位与“为…

双重机器学习DML介绍

本文参考&#xff1a; [1]文心一言回答&#xff1b; 一、核心原理与数学框架 双重机器学习&#xff08;Double Machine Learning, DML&#xff09;由Chernozhukov等学者于2018年提出&#xff0c;是一种结合机器学习与传统计量经济学的因果推断框架。其核心目标是在高维数据和非…

【图像算法 - 21】慧眼识虫:基于深度学习与OpenCV的农田害虫智能识别系统

摘要&#xff1a; 在现代农业生产中&#xff0c;病虫害是影响作物产量和品质的关键因素之一。传统的害虫识别依赖人工巡查&#xff0c;效率低、成本高且易出错。本文将介绍如何利用深度学习与OpenCV构建一套高效的农田害虫智能识别系统。该系统能够自动识别10类常见农业害虫&a…

循环神经网络实战:GRU 对比 LSTM 的中文情感分析(三)

循环神经网络实战&#xff1a;GRU 对比 LSTM 的中文情感分析&#xff08;三&#xff09; 文章目录循环神经网络实战&#xff1a;GRU 对比 LSTM 的中文情感分析&#xff08;三&#xff09;前言数据准备&#xff08;与 LSTM 相同&#xff09;模型搭建&#xff08;GRU&#xff09;…

学习游戏制作记录(制作提示框以及使用键盘切换UI)8.21

1.制作装备提示框创建提示框&#xff0c;添加文本子对象&#xff0c;用来描述名称&#xff0c;类型以及属性加成挂载垂直分配组件和文本大小适配组件&#xff0c;这样图像会根据文本大小来调整自己创建UI_ItemTip脚本并挂载在文本框上&#xff1a;[SerializeField] private Tex…

chapter07_初始化和销毁方法

一、简介 一个Bean&#xff0c;在进行实例化之后&#xff0c;需要进行两种初始化 初始化属性&#xff0c;由PropertyValues进行赋值初始化方法&#xff0c;由ApplicationContext统一调用&#xff0c;例如加载配置文件 Bean的初始化与销毁&#xff0c;共有三种方式&#xff08;注…

open webui源码分析6-Function

一、Functions简介 可以把Tools作为依赖于外部服务的插件&#xff0c;Functions就是内部插件&#xff0c;二者都是用来增强open webui的能力的。Functions是轻量的&#xff0c;高度可定制的&#xff0c;并且是用纯Python编写的&#xff0c;所以你可以自由地创建任何东西——从新…

C2039 “unref“:不是“osgEarth::Symbology::Style”的成员 问题分析及解决方法

在osgEarth2.10中实现多线段连续测量功能时,遇到下图中的错误; 经过测试和验证,主要问题出现在下图圈出代码的定义上 图22-1 对于22-1中的两个变量这样定义是错误的。因为Style类没有继承自osg::Referenced,因此不能与osg::ref_ptr配合使用

GitHub 热榜项目 - 日榜(2025-08-19)

GitHub 热榜项目 - 日榜(2025-08-19) 生成于&#xff1a;2025-08-19 统计摘要 共发现热门项目&#xff1a;12 个 榜单类型&#xff1a;日榜 本期热点趋势总结 本期GitHub热榜呈现三大技术热点&#xff1a;1&#xff09;AI原生开发持续爆发&#xff0c;Archon OS、Parlant等…

ingress 配置ssl证书

模拟环境举例&#xff1a; # 生成带 OU 的证书配置文件 cat > csr.conf <<EOF [ req ] default_bits 2048 prompt no default_md sha256 distinguished_name dn[ dn ] C CN ST Beijing L Beijing O YourCompany, Inc. # 组织名称 (必填) OU DevOps De…

Pandas 合并数据集:concat 和 append

文章目录Pandas 合并数据集&#xff1a;concat 和 append回顾&#xff1a;NumPy 数组的拼接使用 pd.concat 进行简单拼接重复索引将重复索引视为错误忽略索引添加多级索引&#xff08;MultiIndex&#xff09;键使用连接&#xff08;Join&#xff09;方式拼接append 方法Pandas …

2025年5月架构设计师综合知识真题回顾,附参考答案、解析及所涉知识点(七)

本文主要回顾2025年上半年(2025-5-24)系统架构设计师考试上午综合知识科目的选择题,同时附带参考答案、解析和所涉知识点。 2025年5月架构设计师综合知识真题回顾,附参考答案、解析及所涉知识点(一) 2025年5月架构设计师综合知识真题回顾,附参考答案、解析及所涉知识点(…

面向RF设计人员的微带贴片天线计算器

微带贴片天线和阵列可能是仅次于单极天线和偶极天线的最简单的天线设计。这些天线也很容易集成到PCB中&#xff0c;因此通常用于5G天线阵列和雷达等高级系统。这些天线阵列在基谐模式和高阶模式下也遵循一组简单的设计方程&#xff0c;因此您甚至可以在不使用仿真工具的情况下设…

明基RD280U编程显示器深度测评:码农的「第二块键盘」竟然会发光?

文章目录前言一、开箱篇&#xff1a;当理工男遇到「俄罗斯套娃式包装」二、外观篇&#xff1a;深空灰的「代码容器」1. 桌面变形记2. 保护肩颈的人体工学设计三、显示篇&#xff1a;给代码做「光子嫩肤」1. 28寸超大大屏 3:2屏比 4K超清2.专业编程模式&#xff0c;让代码一目…