【复刻论文】企业数字化转型年度报告词频+文本统计

参考文献

[1]吴非,胡慧芷,林慧妍,任晓怡.企业数字化转型与资本市场表现——来自股票流动性的经验证[J].管理世界,2021,37(07)

[2]韩峰,姜竹青.集聚网络视角下企业数字化的生产率提升效应研究[J].管理世界,2023,39(11)

复刻论文缘由

本人为大二学生,上数据科学导论的文本分析课程时,希望顺手锻炼一下学术能力,遂选取以上两篇论文进行参考,希望复刻企业数字化的数据提取过程。

然而在上网搜索的过程中,遇到的很多问题无法得以解决,或者说,有分享出来的都是直接分享爬取好的excel结果,没有看到直接分享代码的;或者说,都是需要收费的。

基于此,本人希望把整个作业结果分享出来,和大家共同研究探讨。

遇到的问题主要如下:

1、如何爬取上市公司年报数据

--> 参考了社区里面另一个大佬的:巨潮资讯网年报爬虫_爬取巨潮资讯网年报-CSDN博客

2、如何将pdf转换成txt

--> 自行探索综合了几个方案,再调整得出的可运行的版本

3、在此基础上,剔除关键词前存在“没”“无”“不”等否定词语的表述,同时也剔除非本公司(包括公司的股东、客户、供应商、公司高管简介介绍在内)的“数字化转型”关键词

--> 本人只剔除了否定表述,对于后者,希望有大佬指点一番

词典

数据说明

本文基于文本挖掘的数字经济词频方法来测算企业数字化水平。

本文根据吴非等(2021)的方法,利用爬虫技术批量搜索了中国沪深A股上市制造业企业2010~2022年期间的年报文本数据,并且使用其词典进行词频统计。

进而借鉴洛克伦和麦克唐纳(2014)及阿西莫格鲁等(2021)的研究,利用上市公司年报文本数据和基于机器学习的“词频—逆文本频率”方法测算企业数字化水平。

企业数字化指标可以表示为:

1、爬取年报

在CSMAR上自行下载所你需要的股票代码,将文件命名为“stockcode.xlsx”,表格内容如图所示:

调整文件夹路径,即可直接运行代码。我这里爬取的是巨潮资讯网的年报数据。 

import os
os.chdir(r"E:\大学课程相关\大二下学期\5 数据科学导论\文本分析")
os.getcwd()
import requests,time,random,json
import pandas as pd

def req(stock,year,org_dict):
    # post请求地址(巨潮资讯网的那个查询框实质为该地址)
    url = "http://www.cninfo.com.cn/new/hisAnnouncement/query"
    # 表单数据,需要在浏览器开发者模式中查看具体格式
    data  = {
        "pageNum":"1",
        "pageSize":"30",
        "tabName":"fulltext",
        "stock":stock + "," + org_dict[stock] ,# 按照浏览器开发者模式中显示的参数格式构造参数
        "seDate":f"{str(int(year)+1)}-01-01~{str(int(year)+1)}-12-31",
        "column":"szse",
        "category":"category_ndbg_szsh",
        "isHLtitle": "true",
        "sortName":"time",
        "sortType": "desc"
        }
    # 请求头
    headers =  {"Content-Length": "201","Content-Type":"application/x-www-form-urlencoded"}
    # 发起请求
    req = requests.post(url,data=data,headers=headers)
    
    if json.loads(req.text)["announcements"]:# 确保json.loads(req.text)["announcements"]非空,是可迭代对象
        for item in json.loads(req.text)["announcements"]:# 遍历announcements列表中的数据,目的是排除英文报告和报告摘要,唯一确定年度报告或者更新版
            if "摘要" not in item["announcementTitle"]:
                if "英文" not in item["announcementTitle"]:
                    if "修订" in item["announcementTitle"] or "更新" in item["announcementTitle"]:
                        adjunctUrl = item["adjunctUrl"] # "finalpage/2019-04-30/1206161856.PDF" 中间部分便为年报发布日期,只需对字符切片即可
                        pdfurl = "http://static.cninfo.com.cn/" + adjunctUrl
                        r = requests.get(pdfurl)
                        f = open("年报" +"/"+ stock + "-" + year + "年度报告" + ".pdf", "wb")
                        f.write(r.content)                       
                        print(f"{stock}-{year}年报下载完成!") # 打印进度
                        break
                    else:
                        adjunctUrl = item["adjunctUrl"] # "finalpage/2019-04-30/1206161856.PDF" 中间部分便为年报发布日期,只需对字符切片即可
                        pdfurl = "http://static.cninfo.com.cn/" + adjunctUrl
                        r = requests.get(pdfurl)
                        f = open("年报" +"/"+ stock + "-" + year + "年度报告" + ".pdf", "wb")
                        f.write(r.content)                       
                        print(f"{stock}-{year}年报下载完成!") # 打印进度
                        break
# 该函数主要是通过http://www.cninfo.com.cn/new/data/szse_stock.json该json数据,找到每个stock对应的orgid,并存储在字典org_dict中
def get_orgid():
    org_dict = {}
    org_json = requests.get("http://www.cninfo.com.cn/new/data/szse_stock.json").json()["stockList"]

    for i in range(len(org_json)):
        org_dict[org_json[i]["code"]] = org_json[i]["orgId"]

    return org_dict
# 获取年报PDF的路径
def load_pdf(code, year):
    file_path = r'E:\大学课程相关\大二下学期\5 数据科学导论\文本分析\年报'  # 自行修改
    file_name = "{}-{}年度报告".format(code,year)
    pdf_path = os.path.join(file_path,file_name)
    return pdf_path
import pandas as pd
import time
import random
import os

if __name__ == "__main__":
    # 读取股票代码信息
    data = pd.read_excel("stockcode.xlsx", converters={'stockcode': str})
    stockcodes = data['stockcode'].tolist()
    org_dict = get_orgid()

    # 年份范围从2010到2022
    years = [str(year) for year in range(2010, 2023)]

    # 遍历股票代码及年份列表
    for stock in stockcodes:
        for year in years:
            pdf_path = load_pdf(stock, year) + ".pdf"
            txt_path = load_pdf(stock, year) + ".txt"

            # 检查对应的PDF文件是否已经存在,如果存在则跳过下载步骤
            if os.path.exists(pdf_path):
                print("PDF文件已存在,跳过下载步骤。")
            else:
                req(stock, year, org_dict)
                time.sleep(random.randint(0, 2))
                

 2、文件转换:将PDF转换成TXT文件

import pandas as pd
import os
from pdfminer.converter import PDFPageAggregator
from pdfminer.layout import *
from pdfminer.pdfparser import PDFParser
from pdfminer.pdfdocument import PDFDocument
from pdfminer.pdfpage import PDFPage,PDFTextExtractionNotAllowed
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
# 获取年报PDF的路径
def load_pdf(code, year):
    file_path = r'E:\大学课程相关\大二下学期\5 数据科学导论\文本分析\年报'  # 自行修改
    file_name = "{}-{}年度报告".format(code,year)
    pdf_path = os.path.join(file_path,file_name)
    return pdf_path
def parsePDF(pdf_path,txt_path):
    # 以二进制读模式打开pdf文档
    fp = open(pdf_path,'rb')

    # 用文件对象来创建一个pdf文档分析器
    parser = PDFParser(fp)

    # pdf文档的对象,与分析器连接起来
    doc = PDFDocument(parser=parser)
    parser.set_document(doc=doc)

    # 如果是加密pdf,则输入密码,新版好像没有这个属性
    # doc._initialize_password()

    # 创建pdf资源管理器 来管理共享资源
    resource = PDFResourceManager()

    # 参数分析器
    laparam=LAParams()

    # 创建一个聚合器
    device = PDFPageAggregator(resource,laparams=laparam)

    # 创建pdf页面解释器
    interpreter = PDFPageInterpreter(resource,device)
    
    # 用来计数页面,图片,曲线,figure,水平文本框等对象的数量
    num_page, num_image, num_curve, num_figure, num_TextBoxHorizontal = 0, 0, 0, 0, 0

    # 获取页面的集合
    for page in PDFPage.get_pages(fp):
        num_page += 1  # 页面增一
        # 使用页面解释器来读取
        interpreter.process_page(page)

        # 使用聚合器来获取内容
        layout = device.get_result()
        # 这里layout是一个LTPage对象 里面存放着 这个page解析出的各种对象 一般包括LTTextBox, LTFigure, LTImage, LTTextBoxHorizontal 等等 想要获取文本就获得对象的text属性,
        for x in layout:
            if isinstance(x,LTImage):  # 图片对象
                num_image += 1
            if isinstance(x,LTCurve):  # 曲线对象
                num_curve += 1
            if isinstance(x,LTFigure):  # figure对象
                num_figure += 1
            if isinstance(x, LTTextBoxHorizontal):  # 获取文本内容
                num_TextBoxHorizontal += 1  # 水平文本框对象增一
                    # 保存文本内容
                with open(txt_path, 'a',encoding='UTF-8',errors='ignore') as f:
                    results = x.get_text()
                    f.write(results + '\n')
# 读取股票代码信息
rawdata = pd.read_excel(r'E:\大学课程相关\大二下学期\5 数据科学导论\文本分析\stockcode.xlsx', sheet_name=0, dtype={'stockcode': str})

# 获取DataFrame的行数
num_rows = len(rawdata)
print(num_rows)

# 年份范围从2010到2022
years = [str(year) for year in range(2010, 2023)]

for iloc in range(num_rows):
    code = rawdata.loc[iloc, 'stockcode']
    print(code)
    
    # 遍历固定的年份范围
    for year in years:
        print(year)
        pdf_path = load_pdf(code, year) + ".pdf"
        txt_path = load_pdf(code, year) + ".txt"
        
        # 检查对应的TXT文件是否已经存在,如果存在则跳过转换步骤
        if not os.path.exists(txt_path):
            print(pdf_path)
            parsePDF(pdf_path, txt_path)
        else:
            print("TXT文件已存在,跳过转换步骤。")

 3、计算指标

import jieba
import pandas as pd
from collections import Counter
import re
import os
import numpy as np

def remove_negations(words):
    negations = set(['非','别','不','没','无','忽','莫','否','没有','还没','毫无','无需','无关'])
    filtered_words = []
    skip = False
    for word in words:
        if word in negations:
            skip = True
        elif skip:
            skip = False
        else:
            filtered_words.append(word)
    return filtered_words

def word_frequency_by_category(text, stopwords, custom_dict, categories):
    words = jieba.cut(text)
    filtered_words = [word for word in words if word not in stopwords]
    filtered_words = remove_negations(filtered_words)
    filtered_words = [word for word in filtered_words if word in custom_dict]
    
    category_freq = Counter()
    for word in filtered_words:
        for category, words_in_category in categories.items():
            if word in words_in_category:
                category_freq[category] += 1
                break
    
    return category_freq

def preprocess_text(text):
    # 去除非中文字符和数字
    text = re.sub(r'[^\u4e00-\u9fa5]', '', text)
    text = re.sub(r'\d+', '', text)
    return text

# 计算指标函数
def calculate_indicators(df):
    # 计算数字化关键词在上市企业 i 第 t 年的年报中的词频
    df['ln(hkit+1)'] = np.log1p(df['词频'].astype(float))
    
    # 计算第 t 年上市企业年报文本总数 Qt
    total_reports = df.groupby('year').size().reset_index(name='Qt')
    df = pd.merge(df, total_reports, on='year', how='left')
    
    # 计算第 t 年包含第 k 个数字化关键词的年报文本数量 qkt
    keyword_counts = df.groupby(['year']).size().reset_index(name='qkt')
    df = pd.merge(df, keyword_counts, on='year', how='left')
    
    # 计算包含第 k 个数字化关键词的逆文本频率 ln(Qt/qkt+1)
    df['ln(Qt/qkt+1)'] = np.log1p(df['Qt'] / (df['qkt'] + 1).astype(float))
    
    # 计算指标 kit =∑k[ln(hkit+1)*ln(Qt/qkt+1)]
    df['k'] = df['ln(hkit+1)'] * df['ln(Qt/qkt+1)']
    kit = df.groupby('year')['k'].sum().reset_index(name='kit')
    df = pd.merge(df, kit, on='year', how='left')
    
    return df

# 读取停用词表
with open('stopwords.txt', 'r', encoding='utf-8') as f:
    stopwords = set(f.read().splitlines())

# 读取自定义词典
custom_dict = set([
    "人工智能", "商业智能", "图像理解投资决策辅助系统", "智能数据分析", "智能机器人", 
    "机器学习", "深度学习", "语义搜索", "生物识别技术", "人脸识别", "语音识别", 
    "身份验证", "自动驾驶", "自然语言处理","大数据", "数据挖掘", "文本挖掘", 
    "数据可视化", "异构数据", "征信", "增强现实", "混合现实", "虚拟现实","云计算", 
    "流计算", "图计算", "内存计算", "多方安全计算", "类脑计算", "绿色计算", 
    "认知计算", "融合架构", "亿级并发", "EB级存储", "物联网", "信息物理系统","区块链", 
    "数字货币", "分布式计算", "差分隐私技术", "智能金融合约","移动互联网", "工业互联网", 
    "移动互联", "互联网医疗", "电子商务", "移动支付", "第三方支付", "NFC支付", 
    "智能能源", "B2B", "B2C", "C2B", "C2C", "O2O", "网联", "智能穿戴", 
    "智慧农业", "智能交通", "智能医疗", "智能客服", "智能家居", "智能投顾", 
    "智能文旅", "智能环保", "智能电网", "智能营销", "数字营销", "无人零售", 
    "互联网金融", "数字金融", "Fintech", "金融科技", "量化金融", "开放银行"
])

# 自定义不同板块及其对应的词语
categories = {
    "人工智能技术": {"人工智能", "商业智能", "图像理解投资决策辅助系统", "智能数据分析", "智能机器人", "机器学习", "深度学习", "语义搜索", "生物识别技术", "人脸识别", "语音识别", "身份验证", "自动驾驶", "自然语言处理"},
    "大数据技术": {"大数据", "数据挖掘", "文本挖掘","数据可视化", "异构数据", "征信", "增强现实", "混合现实", "虚拟现实"},
    "云计算技术":{"云计算", "流计算", "图计算", "内存计算", "多方安全计算", "类脑计算", "绿色计算", "认知计算", "融合架构", "亿级并发", "EB级存储", "物联网", "信息物理系统"},
    "区块链技术":{"区块链", "数字货币", "分布式计算", "差分隐私技术", "智能金融合约"},
    "数据技术运用":{"移动互联网", "工业互联网", "移动互联", "互联网医疗", "电子商务", "移动支付", "第三方支付", "NFC支付", "智能能源", "B2B", "B2C", "C2B", "C2C", "O2O", "网联", "智能穿戴", "智慧农业", "智能交通", "智能医疗", "智能客服", "智能家居", "智能投顾", "智能文旅", "智能环保", "智能电网", "智能营销", "数字营销", "无人零售", "互联网金融", "数字金融", "Fintech", "金融科技", "量化金融", "开放银行"}
}

# 将自定义词典中的词语添加到分词词典中
for word in custom_dict:
    jieba.add_word(word)

# 指定年报文本文件夹路径
folder_path = r'C:\Users\leon\data\03 数据科学导论\第二次小组作业数据\年报'

# 创建一个空的 DataFrame 用于存储所有词频统计结果
all_results_df = pd.DataFrame(columns=['code', 'year', '板块', '词频'])

# 定义预处理函数并计算词频
def preprocess_and_calculate(text):
    text = preprocess_text(text)
    freq_dict = word_frequency_by_category(text, stopwords, custom_dict, categories)
    return freq_dict

# 遍历文件夹中的所有txt文件
for filename in os.listdir(folder_path):
    if filename.endswith(".txt"):
        file_path = os.path.join(folder_path, filename)
        
        code, year_str = filename.split('-')
        year = int(year_str[:4])  # 从文件名中提取年份
        
        with open(file_path, 'r', encoding='utf-8') as f:
            text = f.read()
        
        # 预处理文本并计算词频
        category_freq = preprocess_and_calculate(text)
        
        # 将词频结果存入 DataFrame
        df = pd.DataFrame(category_freq.items(), columns=['板块', '词频'])
        
        # 添加股票代码和年份列
        df['code'] = code
        df['year'] = year
        
        # 调整列的顺序
        df = df[['code', 'year', '板块', '词频']]
        
        # 将结果添加到 all_results_df 中
        all_results_df = pd.concat([all_results_df, df], ignore_index=True)

# 存储指标数据
all_results_with_indicators = calculate_indicators(all_results_df)

# 根据公司代码和年份分组,保留每个公司每年的唯一一个 kit 数据
unique_kit = all_results_with_indicators.groupby(['code', 'year'])['kit'].first().reset_index()

# 存储带有指标的数据
unique_kit.to_excel('指标构建.xlsx', index=False)

欢迎评论区批评指正!

## 介绍 ## 01、数据介绍 数字化转型是指企业在全球数字化变革的背景下,为适应数字经济环境下企业生存发展和市场变化的需要,主动进行的系统性、整体性的转型升级。这个过程涉及利用数字技术,如互联网、物联网、大数据等,对企业战略体系、商业模式、业务流程、生产运营、组织架构等进行全方位、系统化的变革和重塑。 数据名称:上市公司年报-数字化转型(报告词频文本统计) 数据年份:2001-2022年 ## 02、相关数据及指标 股票简称 首次上市年份 注册地址 上市状态 MD&A文本-文本总长度 MD&A文本仅中英文-文本总长度 数字化转型程度-A 数字化转型程度-B 人工智能技术-A 大数据技术-A 云计算技术-A 区块链技术-A 数字技术运用-A 数字技术应用-B 互联网商业模式-B 智能制造-B 现代信息系统-B 人工智能 商业智能 图像理解 投资决策辅助系统 智能数据分析 智能机器人 机器学习 深度学习 语义搜索 生物识别技术 人脸识别 语音识别 身份验证 自动驾驶 自然语言处理 大数据 数据挖掘 文本挖掘 数据可视化 异构数据 征信 增强现实 混合现实 虚拟现实 云计算 流计算 图计算 内存计算 多方安全计算 类脑计算 绿色计算 认知计算 融合架构 亿级并发 EB级存储 物联网 信息物理系统 区块链 数字货币 分布式计算 差分隐私技术 智能金融合约 移动互联网 工业互联网 移动互联 互联网医疗 电子商务 移动支付 第三方支付 NFC支付 智能能源 B2B B2C C2B C2C O2O 网联 智能穿戴 智慧农业 智能交通 智能医疗 智能客服 智能家居 智能投顾 智能文旅 智能环保 智能电网 智能营销 数字营销 无人零售 互联网金融 数字金融 Fintech 金融科技 量化金融 开放银行 数据管理_ 数据挖掘_ 数据网络_ 数据平台_ 数据中心_ 数据科学_ 数字控制_ 数字技术_ 数字通信_ 数字网络_ 数字智能_ 数字终端_ 数字营销_ 数字化_ 大数据_ 云计算_ 云IT_ 云生态_ 云服务_ 云平台_ 区块链_ 物联网_ 机器学习_ 移动互联网_ 工业互联网_ 产业互联网_ 互联网解决方案_ 互联网技术_ 互联网思维_ 互联网行动_ 互联网业务_ 互联网移动_ 互联网应用_ 互联网营销_ 互联网战略_ 互联网平台_ 互联网模式_ 互联网商业模式_ 互联网生态_ 电商_ 电子商务_ Internet_ 互联网+_ 线上线下_ 线上到线下_ 线上和线下_ O2O_ B2B_ C2C_ B2C_ C2B_ 人工智能_ 高端智能_ 工业智能_ 移动智能_ 智能控制_ 智能终端_ 智能移动_ 智能管理_ 智能工厂_ 智能物流_ 智能制造_ 智能仓储_ 智能技术_ 智能设备_ 智能生产_ 智能网联_ 智能系统_ 智能化_ 自动控制_ 自动监测_ 自动监控_ 自动检测_ 自动生产_ 数控_ 一体化_ 集成化_ 集成解决方案_ 集成控制_ 集成系统_ 工业云_ 未来工厂_ 智能故障诊断_ 生命周期管理_ 生产制造执行系统_ 虚拟化_ 虚拟制造_ 信息共享_ 信息管理_ 信息集成_ 信息软件_ 信息系统_ 信息网络_ 信息终端_ 信息中心_ 信息化_ 网络化_ 工业信息_ 工业通信_
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值