名师讲堂|使用 R 语言计算上市公司数字赋能指数(数字技术应用程度指标)

「经济研究」2023 年 6 月刊里面有篇论文 <国内贸易网络、地理距离和供应商本地化>中使用了上市公司数字赋能指数的数据来反映上市公司数字技术的应用程度。该指标的计算方法如下:

其中 D 表示数字赋能指标词典集合,包括如下词语:AI技术、人工智能、计算机技术、信息技术、智能化、自动化、神经网络、虚拟现实、数据科学、数据挖掘、数字化、信息化战略、信息化、生物识别、人脸识别、机器学习、深度学习、自然语言处理、图像识别、语音识别、云计算、云平台、云安全、物联网、大数据(最后一个大数据是我自己加的,感觉不能少了这个)。

TF 表示术语频率或者说词频,IDF 表示逆文档频率指数。TF-IDF 分析在我们的系列课程「R 语言文本分析」(平台链接:https://rstata.duanshu.com/#/brief/course/bf37cf50eef04d38b43541cc52114c96)中讲解过。

TF-IDF 的主要思想是:如果某个词或短语(term)在一篇文章中出现的频率高(TF 高),并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。例如一篇文档的总术语数是 100 ,而词汇 “母牛” 出现了 3 次,那么“母牛”一词在该文档中的词频就是 3/100 = 0.03。计算文件频率 (IDF) 的方法是文件集里包含的文件总数除以测定有多少份文件出现过“母牛”一词。所以,如果“母牛”一词在 1000 份文档出现过,而文件总数是 10000000 份的话,其逆向文件频率就是 ln(10 000000 / 1000) = 4。最后的 tf-idf 的分数为 0.03 x 4 = 0.12。

本课程中我们讲讲解如何爬取上市公司年报文件、pdf 文本提取、中文文本分析以及 TF-IDF 分析。

一家上市公司年报爬取

上市公司年报可以从巨潮资讯网搜索和下载:http://www.cninfo.com.cn/new/commonUrl/pageOfSearch?url=disclosure/list/search

首先获取所有的 pdf 链接。对上述的网站进行分析可以找到 pdf 链接数据在这里:

对着这个项目右键选择 copy as curl (中文的话大致是“以 cURL 格式复制”) 就可以得到 curl 代码了:

curl 'http://www.cninfo.com.cn/new/hisAnnouncement/query' \
-H 'Accept: */*' \
-H 'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8' \
-H 'Connection: keep-alive' \
-H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' \
-H 'Cookie: JSESSIONID=F54CF9328287E65080CD42475D1D0B23; insert_cookie=37836164; routeId=.uc2; _sp_ses.2141=*; _sp_id.2141=b13ee9ff-2493-4f42-a7f5-089a2990e863.1694410049.5.1694427697.1694423114.e98c8005-d826-47b7-8bf0-e994e4d09f2f' \
-H 'Origin: http://www.cninfo.com.cn' \
-H 'Referer: http://www.cninfo.com.cn/new/commonUrl/pageOfSearch?url=disclosure/list/search' \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36' \
-H 'X-Requested-With: XMLHttpRequest' \
--data-raw 'pageNum=1&pageSize=30&column=szse&tabName=fulltext&plate=&stock=000001%2Cgssz0000001&searchkey=&secid=&category=category_ndbg_szsh&trade=&seDate=2020-09-11~2023-09-12&sortName=&sortType=&isHLtitle=true' \
--compressed \
--insecure

然后可以使用这个网站把上面的 curl 语句转换成 R 语言:https://curlconverter.com/r/ ,还可以试着改改其中的一些参数,下面是转换得到的 R 代码:

library(tidyverse)
require(httr)

cookies = c(
`JSESSIONID` = "F54CF9328287E65080CD42475D1D0B23",
`insert_cookie` = "37836164",
`routeId` = ".uc2",
`_sp_ses.2141` = "*",
`_sp_id.2141` = "b13ee9ff-2493-4f42-a7f5-089a2990e863.1694410049.5.1694427697.1694423114.e98c8005-d826-47b7-8bf0-e994e4d09f2f"
)

headers = c(
`Accept` = "*/*",
`Accept-Language` = "zh-CN,zh;q=0.9,en;q=0.8",
`Connection` = "keep-alive",
`Content-Type` = "application/x-www-form-urlencoded; charset=UTF-8",
`Origin` = "http://www.cninfo.com.cn",
`Referer` = "http://www.cninfo.com.cn/new/commonUrl/pageOfSearch?url=disclosure/list/search",
`User-Agent` = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36",
`X-Requested-With` = "XMLHttpRequest"
)

data = list(
`pageNum` = "1",
`pageSize` = "30",
`column` = "szse",
`tabName` = "fulltext",
`plate` = "",
`stock` = "000001,gssz0000001",
`searchkey` = "",
`secid` = "",
`category` = "category_ndbg_szsh",
`trade` = "",
`seDate` = "2020-09-11~2023-09-12",
`sortName` = "",
`sortType` = "",
`isHLtitle` = "true"
)

res <- httr::POST(url = "http://www.cninfo.com.cn/new/hisAnnouncement/query", httr::add_headers(.headers=headers), httr::set_cookies(.cookies = cookies), body = data, encode = "form", config = httr::config(ssl_verifypeer = FALSE))

我们可以试试把 seDate 修改成 “2000-01-01~2023-09-11”(pageSize 也可以试试修改成 100,不过没什么效果):

data = list(
`pageNum` = "1",
`pageSize` = "30",
`column` = "szse",
`tabName` = "fulltext",
`plate` = "",
`stock` = "000002,gssz0000002",
`searchkey` = "",
`secid` = "",
`category` = "category_ndbg_szsh",
`trade` = "",
`seDate` = "2000-01-01~2023-09-11",
`sortName` = "",
`sortType` = "",
`isHLtitle` = "true"
)

res <- httr::POST(url = "http://www.cninfo.com.cn/new/hisAnnouncement/query",
httr::add_headers(.headers=headers),
httr::set_cookies(.cookies = cookies),
body = data, encode = "form",
config = httr::config(ssl_verifypeer = FALSE))

content(res) -> ls

ls$announcements %>%
transpose() %>%
as_tibble() %>%
unnest() %>%
filter(!str_detect(announcementTitle, "摘要")) %>%
select(announcementTitle, adjunctUrl) %>%
mutate(adjunctUrl = paste0("http://static.cninfo.com.cn/", adjunctUrl)) -> df1

df1

#> # A tibble: 15 × 2
#> announcementTitle adjunctUrl
#> <chr> <chr>
#> 1 2022年年度报告 http://static.cninfo.com.cn/finalpage/2023-03-31/12…
#> 2 2021年年度报告 http://static.cninfo.com.cn/finalpage/2022-03-31/12…
#> 3 2020年年度报告 http://static.cninfo.com.cn/finalpage/2021-03-31/12…
#> 4 2019年年度报告 http://static.cninfo.com.cn/finalpage/2020-03-18/12…
#> 5 2018年年度报告 http://static.cninfo.com.cn/finalpage/2019-03-26/12…
#> 6 2017年年度报告 http://static.cninfo.com.cn/finalpage/2018-03-27/12…
#> 7 2015年年度报告(更新后) http://static.cninfo.com.cn/finalpage/2017-04-18/12…
#> 8 2016年年度报告 http://static.cninfo.com.cn/finalpage/2017-03-27/12…
#> 9 2015年年度报告 http://static.cninfo.com.cn/finalpage/2016-03-14/12…
#> 10 2014年年度报告 http://static.cninfo.com.cn/finalpage/2015-03-31/12…
#> 11 2013年年度报告 http://static.cninfo.com.cn/finalpage/2014-03-07/63…
#> 12 2012年年度报告 http://static.cninfo.com.cn/finalpage/2013-02-28/62…
#> 13 2011年年度报告 http://static.cninfo.com.cn/finalpage/2012-03-13/60…
#> 14 2010年年度报告 http://static.cninfo.com.cn/finalpage/2011-03-08/59…
#> 15 2009年

这样就得到了第一页的结果,类似的方法再获取第二页的:

# 第二页
data = list(
`pageNum` = "2",
`pageSize` = "30",
`column` = "szse",
`tabName` = "fulltext",
`plate` = "",
`stock` = "000002,gssz0000002",
`searchkey` = "",
`secid` = "",
`category` = "category_ndbg_szsh",
`trade` = "",
`seDate` = "2000-01-01~2023-09-11",
`sortName` = "",
`sortType` = "",
`isHLtitle` = "true"
)

res <- httr::POST(url = "http://www.cninfo.com.cn/new/hisAnnouncement/query",
httr::add_headers(.headers=headers),
httr::set_cookies(.cookies = cookies),
body = data, encode = "form",
config = httr::config(ssl_verifypeer = FALSE))

content(res) -> ls

ls$announcements %>%
transpose() %>%
as_tibble() %>%
unnest() %>%
filter(!str_detect(announcementTitle, "摘要")) %>%
select(announcementTitle, adjunctUrl) %>%
mutate(adjunctUrl = paste0("http://static.cninfo.com.cn/", adjunctUrl)) -> df2

df2

#> # A tibble: 17 × 2
#> announcementTitle adjunctUrl
#> <chr> <chr>
#> 1 2008年年度报告 http://static.cninfo.com.cn/finalpage/200…
#> 2 2007年年度报告 http://static.cninfo.com.cn/finalpage/200…
#> 3 2006年年度报告(英文版)(调整后) http://static.cninfo.com.cn/finalpage/200…
#> 4 2006年年度报告(调整后) http://static.cninfo.com.cn/finalpage/200…
#> 5 2006年年度报告(英文版) http://static.cninfo.com.cn/finalpage/200…
#> 6 2006年年度报告 http://static.cninfo.com.cn/finalpage/200…
#> 7 万 科 B2005年年度报告(英文) http://static.cninfo.com.cn/finalpage/200…
#> 8 G 万科A2005年年度报告 http://static.cninfo.com.cn/finalpage/200…
#> 9 万 科 A2004年年度报告的补充公告 http://static.cninfo.com.cn/finalpage/200…
#> 10 万 科 A2004年年度报告 http://static.cninfo.com.cn/finalpage/200…
#> 11 万 科 A2004年年度报告(英文) http://static.cninfo.com.cn/finalpage/200…
#> 12 万 科 A2003年年度报告 http://static.cninfo.com.cn/finalpage/200…
#> 13 万 科 A2003年年度报告(英文版) http://static.cninfo.com.cn/finalpage/200…
#> 14 万 科 A2002年年度报告(英文版) http://static.cninfo.com.cn/finalpage/200…
#> 15 万 科 A2002年年度报告 http://static.cninfo.com.cn/finalpage/200…
#> 16 万 科 B2001年年度报告(英文版) http://static.cninfo.com.cn/finalpage/200…
#> 17 深万科A2001年年度报告 http://static.cninfo.com.cn/finalpage/200…

看起来应该没有第三页了,合并 df1 和 df2:

# 合并
bind_rows(df1, df2) %>%
filter(!str_detect(announcementTitle, "英文")) %>%
filter(!str_detect(announcementTitle, "补充公告")) %>%
filter(!announcementTitle %in% c("2015年年度报告", "2006年年度报告")) -> df

然后就可以下载 pdf 文件了:

dir.create("pdf")
lapply(df$adjunctUrl, function(x){
if(!file.exists(paste0("pdf/", basename(x)))) {
try({
download.file(x, paste0("pdf/", basename(x)), mode = "wb")
})
}
}) -> res

多家上市公司年报的爬取

所有可选的公司可以从这里看到:http://www.cninfo.com.cn/new/data/szse_stock.json ,是个 json 文件:

library(jsonlite)
fromJSON("http://www.cninfo.com.cn/new/data/szse_stock.json") -> lst
lst$stockList %>%
as_tibble() %>%
mutate(stext = paste0(code, ",", orgId)) -> codelist

codelist

#> # A tibble: 5,618 × 6
#> code pinyin category orgId zwjc stext
#> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 000001 payh A股 gssz0000001 平安银行 000001,gssz0000001
#> 2 000002 wka A股 gssz0000002 万科A 000002,gssz0000002
#> 3 000004 ghwa A股 gssz0000004 国华网安 000004,gssz0000004
#> 4 000005 stxy A股 gssz0000005 ST星源 000005,gssz0000005
#> 5 000006 szya A股 gssz0000006 深振业A 000006,gssz0000006
#> 6 000007 stqx A股 gssz0000007 *ST全新 000007,gssz0000007
#> 7 000008 szgt A股 gssz0000008 神州高铁 000008,gssz0000008
#> 8 000009 zgba A股 gssz0000009 中国宝安 000009,gssz0000009
#> 9 000010 mlst A股 gssz0000010 美丽生态 000010,gssz0000010
#> 10 000011 swya A股 gssz0000011 深物业A 000011,gssz0000011
#> # ℹ 5,608 more rows

这里我们演示前 5 家公司的年报爬取:

# 检索前 5 家公司的
lapply(1:5, function(i){
print(codelist$zwjc[i])
# 每个公司检索 3 页
lapply(1:3, function(x){
data = list(
`pageNum` = x,
`pageSize` = "30",
`column` = "szse",
`tabName` = "fulltext",
`plate` = "",
`stock` = codelist$stext[i],
`searchkey` = "",
`secid` = "",
`category` = "category_ndbg_szsh",
`trade` = "",
`seDate` = "2000-01-01~2023-09-11",
`sortName` = "",
`sortType` = "",
`isHLtitle` = "true"
)

httr::POST(url = "http://www.cninfo.com.cn/new/hisAnnouncement/query",
httr::add_headers(.headers=headers),
httr::set_cookies(.cookies = cookies),
body = data, encode = "form",
config = httr::config(ssl_verifypeer = FALSE)) %>%
content() -> ls

if (length(ls$announcements) > 0) {
ls$announcements %>%
transpose() %>%
as_tibble() %>%
unnest() %>%
filter(!str_detect(announcementTitle, "摘要")) %>%
select(announcementTitle, adjunctUrl) %>%
mutate(adjunctUrl = paste0("http://static.cninfo.com.cn/", adjunctUrl),
code = codelist$code[i])
}
}) %>%
bind_rows()
}) %>%
bind_rows() -> dfall

dfall %>%
filter(!str_detect(announcementTitle, "英文")) %>%
filter(!str_detect(announcementTitle, "补充公告")) %>%
rename(title = announcementTitle, url = adjunctUrl) %>%
mutate(year = str_extract(title, "\\d{4}")) %>%
mutate(title = paste0(code, "_", year, "_", title)) -> dfall

dfall

#> # A tibble: 125 × 4
#> title url code year
#> <chr> <chr> <chr> <chr>
#> 1 000001_2022_2022年年度报告 http://static.cninfo.com.cn/finalpage… 0000… 2022
#> 2 000001_2021_2021年年度报告 http://static.cninfo.com.cn/finalpage… 0000… 2021
#> 3 000001_2020_2020年年度报告 http://static.cninfo.com.cn/finalpage… 0000… 2020
#> 4 000001_2019_2019年年度报告 http://static.cninfo.com.cn/finalpage… 0000… 2019
#> 5 000001_2018_2018年年度报告 http://static.cninfo.com.cn/finalpage… 0000… 2018
#> 6 000001_2017_2017年年度报告 http://static.cninfo.com.cn/finalpage… 0000… 2017
#> 7 000001_2016_2016年年度报告 http://static.cninfo.com.cn/finalpage… 0000… 2016
#> 8 000001_2015_2015年年度报告 http://static.cninfo.com.cn/finalpage… 0000… 2015
#> 9 000001_2014_2014年年度报告 http://static.cninfo.com.cn/finalpage… 0000… 2014
#> 10 000001_2013_2013年年度报告 http://static.cninfo.com.cn/finalpage… 0000… 2013
#> # ℹ 115 more rows

这里的 pdf 文件很多,为了更快的下载,可以使用多线程:

library(parallel)
makeCluster(8) -> cl
clusterExport(cl, "dfall")
dir.create("pdf2")
parLapply(cl, 1:nrow(dfall), function(x){
if(!file.exists(paste0("pdf2/", dfall$title[x], ".pdf"))) {
try({
download.file(dfall$url[x], paste0("pdf2/", dfall$title[x], ".pdf"), mode = "wb")
})
}
}) -> res

由于里面还包含了一些不合要求的结果,所以还需要手动删除下。

pdf 文本提取

这里的 pdf 都不是扫描文档,可以使用 pdftools 包进行文本提取,提取单个文件的:

# pdf 文本提取
library(pdftools)

# 单个文本的提取
pdftools::pdf_text("pdf2/000006_2022_2022年年度报告.pdf") -> text
text %>%
paste0(collapse = "") %>%
str_remove_all("[\\s\\n\\t\\d[a-z].]") -> text

中文文本分词可以使用 jiebaR 包,在分词前我们需要准备一个停用词词典和一个用户词典:

library(jiebaR)

# 分词引擎:需要停用词字典和用户字典
engine_s <- worker(stop_word = "stopwords.txt", user = "dictionary.txt")

# 分词
segment(text, jiebar = engine_s) %>%
as_tibble() %>%
count(value, sort = T) -> df

df
#> # A tibble: 4,213 × 2
#> value n
#> <chr> <int>
#> 1 振业 404
#> 2 资产 330
#> 3 深圳市 300
#> 4 投资 293
#> 5 股份 293
#> 6 项目 272
#> 7 情况 240
#> 8 房地产 218
#> 9 开发 206
#> 10 价值 200
#> # ℹ 4,203 more rows

其中 dictionary.txt 文件放的就是上面数字赋能指标词典。

read_csv("dictionary.txt", col_names = F) -> word

df %>%
arrange(desc(n)) %>%
dplyr::filter(value %in% word$X1)

#> # A tibble: 1 × 2
#> value n
#> <chr> <int>
#> 1 数字化 3

pdf 文本批量提取

然后我们就可以批量提取所有文件的文本并进行分词了:

# 多个 pdf 文档处理
fs::dir_ls("pdf2") %>%
as.character() %>%
as_tibble() %>%
mutate(text = map_chr(value, function(x){
pdftools::pdf_text(x) %>%
paste0(collapse = "") %>%
str_remove_all("[\\s\\n\\t\\d[a-z].]")
})) -> textdf

textdf

#> # A tibble: 124 × 2
#> value text
#> <chr> <chr>
#> 1 pdf2/000001_2001_深发展A2001年年度报告.pdf "深圳发展银行股份有限公司年年度…
#> 2 pdf2/000001_2002_深发展A2002年年度报告.pdf "深圳发展银行股份有限公司年年度…
#> 3 pdf2/000001_2003_深发展A2003年年度报告.pdf "深圳发展银行股份有限公司年年度…
#> 4 pdf2/000001_2004_深发展A2004年年度报告.pdf "深圳发展银行股份有限公司年年度…
#> 5 pdf2/000001_2005_深发展A2005年年度报告.pdf "深圳发展银行股份有限公司年年度…
#> 6 pdf2/000001_2006_2006年年度报告.pdf "深圳发展银行股份有限公司年年度…
#> 7 pdf2/000001_2007_2007年年度报告.pdf "深圳发展银行股份有限公司年年度…
#> 8 pdf2/000001_2008_2008年年度报告.pdf "深圳发展银行股份有限公司年年度…
#> 9 pdf2/000001_2009_2009年年度报告.pdf "深圳发展银行股份有限公司年年度…
#> 10 pdf2/000001_2010_2010年年度报告.pdf "深圳发展银行股份有限公司年年度…
#> # ℹ 114 more rows

textdf %>%
mutate(seg = map(text, function(x){
segment(x, jiebar = engine_s) %>%
as_tibble() %>%
count(value, sort = T)
})) -> textdf2

textdf2

#> # A tibble: 124 × 3
#> value text seg
#> <chr> <chr> <list>
#> 1 pdf2/000001_2001_深发展A2001年年度报告.pdf "深圳发展银行股份有限公… <tibble>
#> 2 pdf2/000001_2002_深发展A2002年年度报告.pdf "深圳发展银行股份有限公… <tibble>
#> 3 pdf2/000001_2003_深发展A2003年年度报告.pdf "深圳发展银行股份有限公… <tibble>
#> 4 pdf2/000001_2004_深发展A2004年年度报告.pdf "深圳发展银行股份有限公… <tibble>
#> 5 pdf2/000001_2005_深发展A2005年年度报告.pdf "深圳发展银行股份有限公… <tibble>
#> 6 pdf2/000001_2006_2006年年度报告.pdf "深圳发展银行股份有限公… <tibble>
#> 7 pdf2/000001_2007_2007年年度报告.pdf "深圳发展银行股份有限公… <tibble>
#> 8 pdf2/000001_2008_2008年年度报告.pdf "深圳发展银行股份有限公… <tibble>
#> 9 pdf2/000001_2009_2009年年度报告.pdf "深圳发展银行股份有限公… <tibble>
#> 10 pdf2/000001_2010_2010年年度报告.pdf "深圳发展银行股份有限公… <tibble>
#> # ℹ 114 more rows

textdf2 %>%
select(-text) -> textdf2

textdf2 %>%
rename(file = value) %>%
unnest(seg) -> textdf3

textdf3

#> # A tibble: 455,090 × 3
#> file value n
#> <chr> <chr> <int>
#> 1 pdf2/000001_2001_深发展A2001年年度报告.pdf 贷款 235
#> 2 pdf2/000001_2001_深发展A2001年年度报告.pdf 资产 155
#> 3 pdf2/000001_2001_深发展A2001年年度报告.pdf 投资 120
#> 4 pdf2/000001_2001_深发展A2001年年度报告.pdf 报告 118
#> 5 pdf2/000001_2001_深发展A2001年年度报告.pdf 会计报表 108
#> 6 pdf2/000001_2001_深发展A2001年年度报告.pdf 二零零一年 104
#> 7 pdf2/000001_2001_深发展A2001年年度报告.pdf 股份 103
#> 8 pdf2/000001_2001_深发展A2001年年度报告.pdf 董事会 92
#> 9 pdf2/000001_2001_深发展A2001年年度报告.pdf 证券 89
#> 10 pdf2/000001_2001_深发展A2001年年度报告.pdf 合计 86
#> # ℹ 455,080 more rows

TF-IDF 分析

tidytext 包提供了 TF-IDF 的简便方法:

library(tidytext)

textdf3 %>%
bind_tf_idf(term = value, document = file, n = n) %>%
mutate(file = basename(file)) %>%
tidyr::extract(col = file, into = c("code", "year"),
regex = "(.*)_(\\d{4})_") %>%
filter(value %in% word$X1) %>%
group_by(code, year) %>%
summarise(tf_idf = sum(tf_idf, na.rm = T)) %>%
ungroup() -> textdf4

textdf4 %>%
mutate(year = as.numeric(year)) -> textdf4

textdf4

#> # A tibble: 68 × 3
#> code year tf_idf
#> <chr> <dbl> <dbl>
#> 1 000001 2005 0.0000968
#> 2 000001 2006 0.0000325
#> 3 000001 2010 0.0000433
#> 4 000001 2011 0.0000344
#> 5 000001 2012 0.0000524
#> 6 000001 2013 0.000286
#> 7 000001 2014 0.000560
#> 8 000001 2015 0.000930
#> 9 000001 2016 0.00101
#> 10 000001 2017 0.00255
#> # ℹ 58 more rows

这样就得到了每个公司每年的数字赋能指数。

绘图展示

下面我们再使用 ggplot2 绘图展示:

# 绘图
codelist %>%
slice(1:5) %>%
pull(zwjc) %>%
paste0(collapse = "、")

library(ggforce)
textdf4 %>%
ggplot(aes(year, tf_idf, color = code)) +
geom_point() +
geom_bspline(linewidth = 1.2) +
labs(x = "", y = "数字赋能指数(TF-IDF)", color = "",
title = "2001~2022 年 5 家上市公司数字技术应用程度指标计算结果(数字赋能指数)",
subtitle = "数据处理&绘图:微信公众号 RStata",
caption = "数据来源:巨潮资讯网<http://www.cninfo.com.cn/>") +
scale_color_manual(values = c("#e64b35", "#4dbbd5", "#00a087", "#3c5488", "#f39b7f")) +
theme(legend.position = "top",
plot.background = element_rect(fill = "white", color = "white")) +
scale_x_continuous(breaks = seq(2001, 2022, by = 2)) -> p
ggsave("pic1.png", width = 10, height = 7, device = png)

点击这里跳转到 RStata 短书平台获取附件:名师讲堂|使用 R 语言计算上市公司数字赋能指数(数字技术应用程度指标)

评论