基于MySQL的企业专利数据高效查询与统计实现

news2024/11/26 8:22:09

背景

在进行产业链/产业评估工作时,我们需要对企业的专利进行评估,其中一个重要指标是统计企业每一年的专利数量。本文基于MySQL数据库,通过公司名称查询该公司每年的专利数,实现了高效的专利数据统计。

流程

流程图示例

项目流程概述如下:

目标:根据给定的企业名单,查询出每个企业每年的专利数量及专利得分。

任务分为两步:

  1. 构建专利申请人数据表;
  2. 利用Python查询并导出数据至Excel表。

难点与注意事项⚠️

  • 设计高效的专利申请人数据表,以便通过申请人名称快速查询专利信息。

  • 编写高效的企业专利SQL查询语句。

  • 确定专利得分:考虑到一项专利可能有多个申请人,根据申请人的位置来定义不同的得分公式。
    专利得分公式:  s c o r e = 1 p o s i t i o n \text{专利得分公式: } score = \frac{1}{position} 专利得分公式score=position1

构建专利申请人数据表

专利数据库相关的文章:3500多万家专利数据存入MySQL数据库。

由于专利数据包含超过3000万条记录,且每项专利可能有多位申请人,直接检索是否包含目标申请人效率较低。因此,我们构建了一个专利申请人表(patent_p),将每个申请人作为单独的记录,并对申请人字段建立索引,便于快速查询。表结构如下:

CREATE TABLE patent_p (
    id INT AUTO_INCREMENT PRIMARY KEY,
    applicant VARCHAR(255),
    publication_number VARCHAR(31),
    application_date DATE,
    publication_date DATE,
    grant_publication_date DATE,
    score DOUBLE
);

字段说明

  • 专利公开号:作为专利的唯一标识符,便于后续关联专利表。
  • 申请人:每条记录仅包含一个申请人,以便在此字段上建立索引,加速检索。
  • 日期字段:用于按照年份筛选专利数据。

注意:原始专利表中的申请人可能有多位,故在专利申请人表中将每个申请人独立存储,再对申请人字段建立索引,从而大幅提升检索效率。

处理申请人拆分的代码如下所示:

def filter_company(applicant):
    """
    从原始的多个申请人,拆分成一个一个的申请人
    """
    if applicant is None or not isinstance(applicant, str):
        return []
    split_pattern = r"[;;]"
    applicant = re.split(split_pattern, applicant)
    applicant = map(str.strip, applicant)
    return list(filter(lambda x: len(x) >= 4, applicant))

具体的数据导入代码:

import os
import re
import pymysql
import pandas as pd
from tqdm import tqdm

PASSWORD = "数据库密码"
DATABASE = "数据库名"

# 专利字段映射
Patent_Table_Column = {
    "申请人": "applicant",
    "专利公开号": "publication_number",
    "申请日": "application_date",
    "申请公布日": "publication_date",
    "授权公布日": "grant_publication_date",
}


def filter_company(applicant):
    """
    提取中文公司名称,并去除空格
    """
    if applicant is None or not isinstance(applicant, str):
        return []

    split_pattern = r"[;;]"
    applicant = re.split(split_pattern, applicant)
    applicant = map(str.strip, applicant)
    return list(filter(lambda x: len(x) >= 4, applicant))


def insert_sql_by_csv(file_name):
    df = pd.read_csv(file_name, low_memory=False)
    BATCH_SIZE = 3000
    table_column_en = list(Patent_Table_Column.values())

    # 连接到MySQL数据库
    connection = pymysql.connect(
        host="localhost",  # MySQL数据库的主机
        user="root",  # MySQL用户名
        password=PASSWORD,  # MySQL密码
        database=DATABASE,  # 你要插入数据的数据库
        charset="utf8mb4",
        cursorclass=pymysql.cursors.DictCursor,
    )

    try:
        with connection.cursor() as cursor:
            sql = f"""
                    INSERT INTO patent_p ({", ".join(table_column_en)}, score) 
                    VALUES (%s, %s, %s, %s, %s, %s);
                    """.strip()
            batch_data = []

            for _, row in tqdm(df.iterrows(), total=len(df)):
                d = {}
                applicants = []

                for zh_k, en_k in Patent_Table_Column.items():
                    item = row[zh_k]
                    if pd.isna(item):
                        item = None

                    if zh_k == "申请人":
                        applicants = filter_company(item)
                    else:
                        d[en_k] = item

                for pos, applicant in enumerate(applicants):
                    d["applicant"] = applicant
                    d["score"] = 1 / (pos + 1)

                    tmp_values = tuple([d[k] for k in table_column_en + ["score"]])
                    batch_data.append(tmp_values)
                    if len(batch_data) >= BATCH_SIZE:
                        cursor.executemany(sql, batch_data)
                        # 清空批次
                        batch_data = []

            if batch_data:
                cursor.executemany(sql, batch_data)
            connection.commit()

    except Exception as e:
        print(f"插入数据时出现错误: {e}")
        connection.rollback()
    finally:
        connection.close()


if __name__ == "__main__":

    folder = "/xxx/3571万专利申请全量数据1985-2022年/"
    print(f"文件总数: {len(os.listdir(folder))}")
    cnt = 0
    for file_name in os.listdir(folder):
        if file_name.endswith(".csv"):
            cnt += 1
            filename = os.path.join(folder, file_name)
            print(cnt, file_name)
            insert_sql_by_csv(filename)

该表建成后的效果如下所示:
在这里插入图片描述

在数据插入完成后,再添加索引:
如果先添加索引再插入大量数据,速度会很慢;数据全部插入完成后,再添加索引速度会快很多。

使用以下SQL语句为 applicant 添加索引:

CREATE INDEX idx_applicant ON patent_p(applicant);

这条语句会在 patent_p 表的 applicant 列上创建一个索引 idx_applicant,从而提高在该列上进行查询的效率。若不添加索引,查询需要耗时7s左右,添加索引后,在毫秒级别就可以查出结果。

企业专利查询

在构建完企业信息数据库后,我们添加了公司的年度专利统计数据(2016年至2022年各年专利数量及总得分)。最终查询效果如下:

在这里插入图片描述

示例SQL查询语句:

SELECT applicant AS company_name, YEAR(application_date) AS year, COUNT(*) AS cnt, SUM(score) 
FROM patent_p 
WHERE applicant='深圳大学' 
GROUP BY YEAR(application_date);

查询结果如下所示:
在这里插入图片描述

查询结果解释

该查询语句的作用如下:

  1. select 子句

    • applicant as company_name:将applicant列重命名为company_name,表示公司名称。
    • YEAR(application_date) as year:提取application_date的年份,并将其命名为year
    • count(*) as cnt:计算每年提交的专利申请数量。
    • sum(score):计算该公司每年所有专利申请的得分总和。
  2. from 子句:从patent_p表中获取数据。

  3. where 子句:筛选出applicant字段值等于指定公司名称的记录。

  4. group by 子句:按application_date的年份分组,统计每年的数据。

该查询将返回指定公司每年专利申请数量(cnt)及年度专利得分(sum(score))。具体Python代码实现如下:

import os
import pandas as pd
import pymysql
# import argparse

database = "数据库名"
password = "数据库密码"


connection = pymysql.connect(
    host="localhost",  # MySQL数据库的主机
    user="root",       # MySQL用户名
    password=password, # MySQL密码
    database=database, # 插入数据的数据库
    charset="utf8mb4",
    cursorclass=pymysql.cursors.DictCursor,
)

columns = list(range(1985, 2024)) + ["专利件数", "专利得分"]


def get_patent_statistics_by_name(name):
    if not name:
        return {}

    sql = f"""select applicant as company_name, YEAR(application_date) as year, count(*) as cnt, sum(score) from patent_p 
    where applicant='{name}'
    group by YEAR(application_date);
    """
    with connection.cursor() as cursor:
        data = cursor.execute(sql)
        data = cursor.fetchall()

    ans = {}
    cnt = 0
    score = 0

    for k in columns:
        ans[k] = None

    for item in data:
        cnt += item.get("cnt", 0)
        score += item.get("sum(score)", 0)

        year = item.get("year", None)
        if year:
            ans[year] = item.get("cnt", 0)

    ans["专利得分"] = score
    ans["专利件数"] = cnt
    return pd.Series(ans)


def add_patent_data(input_file, company_name_field="企业名称"):

    print("open", input_file)
    # 读取 CSV 文件
    df = pd.read_csv(input_file, low_memory=False)
    
    df[columns] = df[company_name_field].apply(get_patent_statistics_by_name)

    folder_path = os.path.dirname(input_file)
    output_file = os.path.basename(input_file).split(".")[0] + "_专利统计.xlsx"
    # 保存更新后的数据到 CSV 文件
    output_file = os.path.join(folder_path, output_file)
    
    df.to_excel(output_file, index=False)
    print(f"专利数据已成功添加到文件:{output_file}")


if __name__ == "__main__":
    
    # parser = argparse.ArgumentParser(description="Add patent counts to industry.csv")
    # parser.add_argument("input_file", help="The input CSV file with industry data")
    # parser.add_argument(
    #     "-name", "--name", default="企业名称", help="The column name for company names"
    # )
    # args = parser.parse_args()

    # # 调用函数处理文件
    # add_patent_data(args.input_file, args.name)
    
    folder = "/.../pku_industry/csv_folder_test"
    for file in os.listdir(folder):
        if not file.endswith(".csv"):
            continue
        file_name = os.path.join(folder, file)
        add_patent_data(file_name)

    connection.close()

经过上述专利申请人表的构建流程,能够大幅提升企业专利信息的检索速度,为产业链分析提供强大的数据支持。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

盘点 2024 十大免费/开源 WAF

WAF 是 Web Application Firewall 的缩写,也被称为 Web 应用防火墙。区别于传统防火墙,WAF 工作在应用层,对基于 HTTP/HTTPS 协议的 Web 系统有着更好的防护效果,使其免于受到黑客的攻击。 近几年经济增速开始放缓,科…

鸿蒙进阶-AlphabetIndexer组件

大家好,这里是鸿蒙开天组,今天我们来学习AlphabetIndexer组件,喜欢就点点关注吧! 通过 AlphabetIndexer 组件可以与容器组件结合,实现导航联动,以及快速定位的效果 核心用法 AlphabetIndexer不是容器组件…

【Unity】【游戏开发】Sprite背景闪烁怎么解决

【现象】 VR游戏中,给作为屏幕的3D板子加上Canvas后再加背景image,运行时总是发现image闪烁不定。 【分析】 两个带颜色的object在空间上完全重合时也遇到过这样的问题,所以推测是Canvas的image背景图与木板的面重合导致。 【解决方法】 …

sublime Text中设置编码为GBK

要在sublime Text中设置编码为GBK,请按照以下步骤操作 1.打开Sublime Text编辑器, 2.点击菜单栏中的“Preferences”(首选项)选项,找打Package Control选项。 3.点击Package Control,随后搜索Install Package并点击,如下图 4.再…

队列与栈的代码对比(Java)

目录 链表实现队列 数组实现队列 链表实现栈 数组实现栈 图片: 链表实现队列 package Queue;import java.util.Iterator;public class LinkedListQueue <E> implements Queue<E>, Iterable<E>{//单向环形哨兵链表//节点类private static class Node<…

一些常规IP核功能

一,util_vector_logic util_vector_logic 主要支持以下类型的逻辑操作: 逻辑与(AND): 当所有输入都为1时,输出为1,否则为0。逻辑或(OR): 当任意输入为1时,输出为1,否则为0。逻辑非(NOT): 当输入为1时,输出为0;输入为0时,输出为1。异或(XOR): 当输入中有奇…

Docker篇(Docker安装)

目录 一、Centos7.x 1. yum 包更新到最新 2. 安装需要的软件包 3. 设置 yum 源为阿里云 4. 安装docker 5. 安装后查看docker版本 6. 设置ustc镜像源 二、CentOS安装Docker 前言 1. 卸载&#xff08;可选&#xff09; 2. 安装docker 3. 启动docker 4. 配置镜像加速 …

【c++ gtest】使用谷歌提供的gtest和抖音豆包提供的AI大模型来对代码中的函数进行测试

【c gtest】使用谷歌提供的gtest和抖音豆包提供的AI大模型来对代码中的函数进行测试 下载谷歌提供的c测试库在VsCode中安装抖音AI大模型找到c项目文件夹&#xff0c;使用VsCode和VS进行双开生成gtest代码进行c单例测试 下载谷歌提供的c测试库 在谷歌浏览器搜索github gtest, 第…

google adsense广告费中国收款结算被银行拒解决办法

多年前搞了几个网站&#xff0c;挂了谷歌google adsense广告&#xff0c;不知道不觉到了100美金最低结算&#xff0c;谷歌给我打款&#xff0c;之前是绑定交银银行的。被银行镜内登陆谷歌不合法不合规给拒绝入账&#xff0c;把美金退回了&#xff0c;怎么办&#xff1f; googl…

蓝桥杯 区间移位--二分、枚举

题目 代码 #include <stdio.h> #include <string.h> #include <vector> #include <algorithm> #include <iostream> using namespace std; struct node{ int a,b; }; vector<node> q; bool cmp(node x,node y){ return x.b <…

书生第四期实训营基础岛——L1G1000书生大模型全链路开源体系

书生浦语大模型开源开放体系 书生浦语开源一周年历史 2023.7.6&#xff1a;InternLM-7B开源率先免费商用发布全链条开源工具体系2023.9.20&#xff1a;InternLM-20B开源&#xff0c;开源工具链全线升级2024.1.17&#xff1a;InternLM2开源&#xff0c;性能超最新同量级开源模…

单元测试(Junit)

系统—模块—子模块&#xff0c;子模块中不可分割的程序单元的测试&#xff0c;单元的粒度根据实际情况可能是 类或方法等。 面向对象编程中&#xff0c;最小单元就是方法。 单元测试目的是在集成测试和功能测试之前对系统可测试单元进行逐一检查和验证。 单元测试基本原则 …

MySQL表的增删改查(CRUD3约束)

这次我们开始先不复习嗷&#xff0c;等到把数据表的删除说完咱们统一&#xff0c;总结书写 1.数据表的删除&#xff1a; 语法&#xff1a; 1. 使用 DROP TABLE 语句删除单个表 基本语法&#xff1a;DROP TABLE [IF EXISTS] table_name; table_name是要删除的表的名称。IF EXIS…

go中Println和Printf的区别

Don’t worry , just coding! 内耗与overthinking只会削弱你的精力&#xff0c;虚度你的光阴&#xff0c;每天迈出一小步&#xff0c;回头时发现已经走了很远。 go中Println和Printf的区别 package mainimport ( "fmt" )//TIP To run your code, right-click the c…

【系统面试篇】进程和线程类(1)(笔记)——区别、通讯方式、同步、互斥、锁分类

目录 一、问题综述 1. 进程和线程的区别&#xff1f; 2. 进程的状态有哪些&#xff1f; 3. 进程之间的通信方式? &#xff08;1&#xff09;管道 &#xff08;2&#xff09;消息队列 &#xff08;3&#xff09;共享内存 &#xff08;4&#xff09;信号量 &#xff08…

编译安装并刷写高通智能机器人SDK

The Qualcomm Intelligent Robotics Product SDK (QIRP SDK) 高通智能机器SDK基于ROS2进行开发&#xff0c;此SDK适用于高通linux发行版本&#xff0c;QIRPSDK中提供以下内容&#xff1a; ROS 包中用于支持机器人应用程序开发的参考代码 用于评估机器人平台的端到端场景示例集…

网页版五子棋—— WebSocket 协议

目录 前言 一、背景介绍 二、原理解析 1.连接过程&#xff08;握手&#xff09; 2.报文格式 三、代码示例 1.服务端代码 &#xff08;1&#xff09;TestAPI 类 &#xff08;2&#xff09;WebSocketConfig 类 2.客户端代码 3.代码演示 结尾 前言 从本篇文章开始&am…

鸿蒙应用开发:下载功能

鸿蒙系统不断发展&#xff0c;有与安卓、iOS 形成三足鼎立之势&#xff0c;且其在智能手机、智能穿戴、车载、家居等行业领域的应用越来越广泛。作为开发者&#xff0c;如何抓住鸿蒙生态崛起的机遇&#xff0c;解决开发挑战&#xff0c;创造更好的应用体验&#xff1f;欢迎您和…

小白直接冲!BiTCN-BiLSTM-Attention双向时间卷积双向长短期记忆神经网络融合注意力机制多变量回归预测

小白直接冲&#xff01;BiTCN-BiLSTM-Attention双向时间卷积双向长短期记忆神经网络融合注意力机制多变量回归预测 目录 小白直接冲&#xff01;BiTCN-BiLSTM-Attention双向时间卷积双向长短期记忆神经网络融合注意力机制多变量回归预测效果一览基本介绍程序设计参考资料 效果一…

如何绘制产业链图谱?

绘制产业链图谱是一个系统性的工作&#xff0c;涉及到对产业的深入理解和分析。对于一般产业绘制产业图谱的步骤&#xff0c;我们可以参照以下流程&#xff1a; 1.明确目标产业链&#xff1a;确定要分析的产业链&#xff0c;比如新材料、新能源、智能制造等&#xff0c;这通常…