R 语言:调用百度文心千帆大模型进行文本分析与文本主要内容提取
今年年初给大家分享过一份 银保监本级、分局本级、机关行政处罚信息数据(截止 2023 年 2 月 13 日)(https://rstata.duanshu.com/#/brief/course/d9f672e0087c4f3bbe3c99fdb8c864d2) 数据。实际上这些行政处罚信息包含多种形式的,大体上是处罚决定书和处罚信息公开表,由于处罚决定书的内容比较混乱,难以整理成表格数据,所以就没有整理。
百度文心一言最近开放了 API 接口,于是我就想是不是可以调用文心一言的 API 接口自动处理这些处罚决定书文本来提取主要信息。
申请文心千帆大模型内测
首先我们需要申请文心千帆大模型内测的资格,网址是这个:https://cloud.baidu.com/product/wenxinworkshop?track=ae35a3396ecb3afe68e19773b574a198b11ace12bfeed89c
然后在文心千帆控制台创建应用:https://console.bce.baidu.com/qianfan/ais/console/applicationConsole/application
由于本课程讲解的 ERNIE-Bot 模型的调用是需要付费的,所以可以先给自己的账户充点钱,10 块钱即可。
价格如下,调用一次的价格差不多 1 分钱左右:
创建应用后可以应用列表中可以看到自己的 API Key 和 Secret Key:https://console.bce.baidu.com/qianfan/ais/console/applicationConsole/application ,注意保存好。
大家注意把课程代码中的 API key 和 Secret Key 替换成自己的。
最后再阅读 API 使用文档即可使用了:https://cloud.baidu.com/doc/WENXINWORKSHOP/s/jlil56u11 。本课程中将以 ERNIE-Bot 的使用为例进行讲解。
银保监处罚决定书关键信息提取
附件中我准备了一些 doc 格式的 word 文档,是银保监处罚决定书,例如 1091075.doc
文件:
我们的目标是从中提取如下变量:
年份 标题 处罚决定书文号 主要违法违规事实或案由 处罚依据 处罚决定 作出处罚决定的机关名称 作出处罚决定的日期 被处罚个人姓名 被处罚单位名称 被处罚单位的法定代表人或主要负责人姓名 发布时间
提供的示例数据是 doc 文件,可以使用 R 语言的 textreadr 包进行读取转换:
# 安装 textreadr 包
# install.packages("pacman")
# pacman::p_load_gh("trinker/textreadr")
library(textreadr)
library(tidyverse)
read_dir("doc") -> docdf
docdf
#> Table: [476 x 2]
#>
#> document content
#> 1 1052126 林茂华:\n 我局于2021年7月30日向你送达《行政处罚决定书》(冀银保
#> 2 1052594 本银保监罚决字〔2022〕14号\n\n\n 被处罚单位名称:太平人寿保险有限
#> 3 1052596 本银保监罚决字〔2022〕15号\n\n 被处罚人姓名:邢义东\n 住
#> 4 1052597 本银保监罚决字〔2022〕16号\n\n\n 被处罚人姓名:黄绍民\n
#> 5 1052608 中国银保监会益阳监管分局\n
#> 6 1053002 滨银保监罚决字〔2022〕28号\n\n\n 当事人:中国太平洋人寿保险股份有
#> 7 1053005 滨银保监罚决字〔2022〕37号\n\n\n 姓名:王煜\n 身份证种类
#> 8 1053007 滨银保监罚决字〔2022〕39号\n\n\n 姓名:张海瑞\n 身份证种
#> 9 1053025 莱银保监罚决字〔 2022 〕 4 号\n\n 当事人:苏平\n 身
#> 10 1053029 莱银保监罚决字〔2022〕3 号\n\n 当事人:中国人民财产保险股份有限公
#> .. ... ...
docdf %>%
as_tibble() %>%
mutate(content = str_squish(content),
length = str_length(content)) %>%
arrange(desc(length)) -> docdf
# 保存
docdf
#> # A tibble: 476 × 3
#> document content length
#> <chr> <chr> <int>
#> 1 1074539 当事人:中国平安人寿保险股份有限公司湖北分公司 地 址:武汉市… 3850
#> 2 1066786 当事人:长安责任保险股份有限公司宜昌中心支公司 地址:湖北省… 2751
#> 3 1082815 当事人:英大泰和财产保险股份有限公司黄石中心支公司 地址:湖… 2553
#> 4 1068576 当事人:湖北盛世国寿保险代理有限公司 地 址:武汉市江汉区新华… 2476
#> 5 1060520 东银保监罚决字〔2022〕21号 当事人:泰康人寿保险有限责任公司… 2474
#> 6 1074537 当事人:中英人寿保险有限公司湖北分公司 地 址:武汉市硚口区中… 2377
#> 7 1074533 当事人:英大泰和财产保险股份有限公司湖北分公司 地 址:武汉市… 2313
#> 8 1058527 当事人:湖北汇鑫联创保险销售服务有限责任公司 地址:湖北省十… 2110
#> 9 1062605 当 事 人:广东轻松保保险经纪有限公司 住 所:珠海市横琴新区宝… 2079
#> 10 1084950 (晋中银保监罚决字〔2022〕29号) 当事人:阳光人寿保险股份有… 1959
#> # ℹ 466 more rows
不过有些 doc 文件似乎有问题,无法处理。我们把这些文件筛选出来:
# 创建 errordoc 文件夹
dir.create("errordoc")
# 所有的 doc 文件
fs::dir_ls("doc") %>%
as.character() %>%
as_tibble() -> alldocuments
# 读取成功的 doc 文件
docdf %>%
select(value = document) %>%
mutate(value = paste0("doc/", value, ".doc")) -> successdf
# 使用 anti_join() 提取没成功的
alldocuments %>%
anti_join(successdf) -> faildf
# 把这些文件存放到 errordoc 文件夹
map(faildf$value, function(x){
file.copy(x,
str_replace(x, "doc/", "errordoc/"))
}) -> res
这些文件可以使用 word 打开,另存为 doc 文件再放回到 doc 文件夹中。然后再重复最初的 R 代码即可。这里因为时间关系,我就不再手动一个个操作了。
docdf %>%
filter(length <= 1800) %>%
slice(1:10) -> usedocdf
usedocdf
#> # A tibble: 10 × 3
#> document content length
#> <chr> <chr> <int>
#> 1 1057467 (晋银保监罚决字〔2022〕44号) 当事人:华农财产保险股份有限… 1751
#> 2 1090857 吉银保监罚决字〔2023〕3号 当事人:中国人寿财产保险股份有限公… 1738
#> 3 1057465 (晋银保监罚决字〔2022〕42号) 当事人:李茹梅 住址:山西省太… 1721
#> 4 1064676 菏银保监罚决字〔2022〕112号 当事人:周凯 身份证号码:3709021… 1721
#> 5 1057466 (晋银保监罚决字〔2022〕43号) 当事人:郭勇 住址:山西省太原… 1717
#> 6 1084722 当事人:永安财产保险股份有限公司湖北分公司 地 址:湖北省武汉… 1701
#> 7 1055966 (晋银保监罚决字〔2022〕31号) 当事人:合众人寿保险股份有限… 1695
#> 8 1066189 新银保监罚决字〔2022〕73号 被处罚个人姓名:周晓伟 所在单位名… 1687
#> 9 1071201 营银保监罚决字〔2022〕12号 当事人:中国平安人寿保险股份有限… 1679
#> 10 1068583 当事人:人保汽车保险销售服务有限公司湖北省分公司 地 址:武汉… 1666
# 也可以取出这 10 篇文档方便后面的比对
dir.create("usedoc")
map(usedocdf$document, function(x){
file.copy(paste0("doc/", x, ".doc"),
paste0("usedoc/", x, ".doc"))
}) -> res
ERNIE-Bot 模型接口的使用
按照 API 文档的介绍,ERNIE-Bot 的使用分两步:
# 步骤一,获取access_token,替换下列示例中的API Key与Secret Key
curl 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=[API Key]&client_secret=[Secret Key]'
# 步骤二,调用本文API,使用步骤一获取的access_token,替换下列示例中的”调用接口获取的access_token“
curl -XPOST 'https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions?access_token=[步骤一调用接口获取的access_token]' -d '{
"messages": [
{"role":"user","content":"介绍一下你自己"}
]
}' | iconv -f utf-8 -t utf-8
curl 是一个 DOS/Shell 命令,Win10 之后的系统或者 Mac 系统都可以直接使用,旧版本的 Windows 系统需要自行安装,具体可以百度搜索下教程。在 R 语言中可以使用 httr 进行 curl 请求:
这里的代码也可以使用 https://curlconverter.com/r/ 生成。
首先创建一个对话:
# 注意这里需要使用自己的 API key 和 Secret key
library(httr)
params = list(
`grant_type` = "client_credentials",
`client_id` = "z9kmWfmopgL6xXicRjFMzkG9",
`client_secret` = "rIbhETrv7n5bVFH7octw6aM9Hd594h1v"
)
GET(url = "https://aip.baidubce.com/oauth/2.0/token", query = params) %>%
content() -> lst
lst$session_secret -> access_token
access_token
#> [1] "3453013ffe161c35ba6ed0deb4be881e"
然后就可以循环提问了:
为了便于处理,所有的提问我都采取这种格式:
阅读这段话:“……”,提取年份、标题、处罚决定书文号、主要违法违规事实或案由、处罚依据、处罚决定、作出处罚决定的机关名称、作出处罚决定的日期、被处罚个人姓名、被处罚单位名称、被处罚单位的法定代表人或主要负责人姓名 、发布时间、罚款金额信息。结果使用文本表示,用数字对结果进行编号。
# 为了避免网络中断等问题,还是把每次的提问结果保存好:
dir.create("rds")
lapply(1:nrow(usedocdf), function(x){
if (!file.exists(paste0("rds/", usedocdf$document[x], ".rds"))) {
POST(url = paste0("https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions?access_token=", access_token),
body = paste0('{"messages":[{"role":"user","content":"阅读这段话:“',
usedocdf$content[x],
'”,提取年份、标题、处罚决定书文号、主要违法违规事实或案由、处罚依据、处罚决定、作出处罚决定的机关名称、作出处罚决定的日期、被处罚个人姓名、被处罚单位名称、被处罚单位的法定代表人或主要负责人姓名、发布时间、罚款金额信息。结果使用文本表示,用数字对结果进行编号"}]}')) %>%
content() %>%
write_rds(paste0("rds/", usedocdf$document[x], ".rds"))
}
}) -> res
read_rds("rds/1057466.rds") -> lst
lst$result
#> [1] "1. 年份:2022\n2. 标题:晋银保监罚决字〔2022〕43号\n3. 处罚决定书文号:晋银保监罚决字〔2022〕43号\n4. 主要违法违规事实或案由:\na. 未按规定使用经备案的保险费率\nb. 编制虚假的财务、业务资料\nc. 跨省经营保险业务\n5. 处罚依据:\na. 《中华人民共和国保险法》第一百三十五条“其他保险险种的保险条款和保险费率,应当报保险监督管理机构备案”和《财产保险公司保险条款和保险费率管理办法》第二十七条“各保险机构应当严格执行经中国保监会批准或者备案的保险条款和保险费率,不得违反本办法规定改变保险条款或者保险费率”的规定。\nb. 《中华人民共和国保险法》第八十六条“保险公司应当按照保险监督管理机构的规定,报送有关报告、报表、文件和资料。保险公司的偿付能力报告、财务会计报告、精算报告、合规报告及其他有关报告、报表、文件和资料必须如实记录保险业务事项,不得有虚假记载、误导性陈述和重大遗漏”的规定。\nc. 《保险公司管理规定》第四十一条“保险公司的分支机构不得跨省、自治区、直辖市经营保险业务,本规定第四十二条规定情形和中国保监会另有规定的除外”的规定。\n6. 处罚决定:\na. 对郭勇给予警告,并处1万元罚款。\nb. 对郭勇给予警告,并处1万元罚款。\nc. 对郭勇给予警告,并处1000元罚款。\n7. 作出处罚决定的机关名称:中国银保监会山西监管局\n8. 作出处罚决定的日期:2022年6月14日\n9. 被处罚个人姓名:郭勇\n10. 被处罚单位名称:华农财产保险股份有限公司山西分公司\n11. 被处罚单位的法定代表人或主要负责人姓名:无\n12. 发布时间:2022年6月14日\n13. 罚款金额:1万元、1万元、1000元"
等所有的文档都处理好了再合并结果:
usedocdf %>%
mutate(result = map_chr(document, function(x){
read_rds(paste0("rds/", x, ".rds")) -> lst
lst$result
})) -> usedocdf2
usedocdf2
#> # A tibble: 10 × 4
#> document content length result
#> <chr> <chr> <int> <chr>
#> 1 1057467 (晋银保监罚决字〔2022〕44号) 当事人:华农财产保险股… 1751 "1. …
#> 2 1090857 吉银保监罚决字〔2023〕3号 当事人:中国人寿财产保险股… 1738 "1. …
#> 3 1057465 (晋银保监罚决字〔2022〕42号) 当事人:李茹梅 住址:… 1721 "1. …
#> 4 1064676 菏银保监罚决字〔2022〕112号 当事人:周凯 身份证号码:… 1721 "1. …
#> 5 1057466 (晋银保监罚决字〔2022〕43号) 当事人:郭勇 住址:山… 1717 "1. …
#> 6 1084722 当事人:永安财产保险股份有限公司湖北分公司 地 址:湖… 1701 "1. …
#> 7 1055966 (晋银保监罚决字〔2022〕31号) 当事人:合众人寿保险股… 1695 "1. …
#> 8 1066189 新银保监罚决字〔2022〕73号 被处罚个人姓名:周晓伟 所… 1687 "1. …
#> 9 1071201 营银保监罚决字〔2022〕12号 当事人:中国平安人寿保险股… 1679 "1. …
#> 10 1068583 当事人:人保汽车保险销售服务有限公司湖北省分公司 地 … 1666 "1. …
然后就可以提取所需要的信息了:
usedocdf2 %>%
select(-content, -length) %>%
mutate(result = str_replace_all(result, "\\n", " "),
result = str_replace_all(result, ":", ":")) %>%
tidyr::extract(
col = "result",
into = c("年份", "标题", "处罚决定书文号", "主要违法违规事实或案由",
"处罚依据", "处罚决定", "作出处罚决定的机关名称",
"作出处罚决定的日期", "被处罚个人姓名", "被处罚单位名称",
"被处罚单位的法定代表人或主要负责人姓名", "发布时间", "罚款金额"),
regex = "1\\. 年份:(.*) 2\\. 标题:(.*) 3\\. 处罚决定书文号:(.*) 4\\. 主要违法违规事实或案由:(.*) 5\\. 处罚依据:(.*) 6\\. 处罚决定:(.*) 7\\. 作出处罚决定的机关名称:(.*) 8\\. 作出处罚决定的日期:(.*) 9\\. 被处罚个人姓名:(.*) 10\\. 被处罚单位名称:(.*) 11\\. 被处罚单位的法定代表人或主要负责人姓名:(.*) 12\\. 发布时间:(.*) 13\\. 罚款金额:(.*)",
remove = F
) %>%
mutate(年份 = str_remove_all(年份, "年")) %>%
type_convert() -> usedocdf2
usedocdf2
#> # A tibble: 10 × 15
#> document result 年份 标题 处罚决定书文号 主要违法违规事实或案由 处罚依据
#> <dbl> <chr> <dbl> <chr> <chr> <chr> <chr>
#> 1 1057467 1. 年份… 2022 晋银… 晋银保监罚决字… - 未按规定使用经备案… - 《中…
#> 2 1090857 1. 年份… 2023 吉银… 吉银保监罚决字… - 未严格执行车险条款… - 《中…
#> 3 1057465 1. 年份… 2022 晋银… 晋银保监罚决字… a. 未按规定使用经备案… a. 《中…
#> 4 1064676 1. 年份… 2022 菏银… 菏银保监罚决字… a. 给予投保人保险合同… a. 《中…
#> 5 1057466 1. 年份… 2022 晋银… 晋银保监罚决字… a. 未按规定使用经备案… a. 《中…
#> 6 1084722 1. 年份… 2022 对永… <NA> 编制虚假资料 《中华…
#> 7 1055966 1. 年份… 2022 晋银… 晋银保监罚决字… - 编制虚假财务资料 -… - 《中…
#> 8 1066189 1. 年份… 2022 新银… 新银保监罚决字… - 给予被保险人保险合… - 《中…
#> 9 1071201 1. 年份… 2022 营银… 营银保监罚决字… - 保险代理人欺骗投保… - 《中…
#> 10 1068583 1. 年份… 2022 中国… 汉银保监罚决字… - 给予投保人或被保险… 《中华…
#> # ℹ 8 more variables: 处罚决定 <chr>, 作出处罚决定的机关名称 <chr>,
#> # 作出处罚决定的日期 <chr>, 被处罚个人姓名 <chr>, 被处罚单位名称 <chr>,
#> # 被处罚单位的法定代表人或主要负责人姓名 <chr>, 发布时间 <chr>,
#> # 罚款金额 <chr>
# 保存
usedocdf2 %>%
writexl::write_xlsx("处理结果.xlsx")
看起来效果还挺不错!
应用这个技术就可以快速处理文本数据并提取关键变量了!
直播信息
为了让大家更好的理解上面的内容,欢迎各位培训班会员参加明晚 8 点的直播课 「R 语言:调用百度文心千帆大模型进行文本分析与文本主要内容提取」
直播地址:腾讯会议(需要报名 RStata 培训班参加) 讲义材料:需要报名 RStata 培训班,详情可阅读:一起来学习 R 语言和 Stata 啦!学习过程中遇到的问题也可以随时提问!
更多关于 RStata 会员的更多信息可添加微信号 r_stata 咨询:
附件下载(点击文末的阅读原文即可跳转):
https://rstata.duanshu.com/#/brief/course/ac74461a5d12460b80538877a8242b18