使用 Stata 调用本地部署的大语言模型进行文本主要内容提取——历年政府工作报告中的经济增长目标提取(deepseek版本)

本推文内容类似下面的这个课程,感兴趣的小伙伴可以结合该课程的视频学习:

使用 Stata 调用本地部署的大语言模型进行文本主要内容提取——历年政府工作报告中的经济增长目标提取:https://rstata.duanshu.com/#/brief/course/42f4af4244df4e26b1f8b625ab5e321d


之前给大家分享过使用 Stata 调用百度文心千帆大模型进行文本分析与文本主要内容提取的方法:

Stata:调用百度文心千帆大模型进行文本分析与文本主要内容提取:https://rstata.duanshu.com/#/brief/course/6aac8b39269d431eaa9017b25a966463

不过调用这个接口是需要付费的,如果要进行处理的文本很多并不划算,因此今天再给大家分享一个新的方法。也就是通过部署在本地的大模型进行文本内容提取。

安装 Ollama

通过 Ollama 可以快速在本地部署一些常用的大模型。可以根据自己的系统从这里安装下载:https://github.com/ollama/ollama

MacOS 下载 Ollama 链接: https://ollama.com/download/Ollama-darwin.zip

Windows 下载 Ollama 链接: https://ollama.com/download/OllamaSetup.exe

Windows 用户对安装有问题的可以参考这个推文:https://blog.csdn.net/scj0725/article/details/138087028

安装完之后就可以打开 DOS(Windows 用户)或 Terminal(Mac 用户)使用相应的模型了,这里使用的是 deepseek-r1:1.5b 模型:

ollama run deepseek-r1:1.5b

第一次运行的时候是安装改模型,会需要等待较长时间,后续再运行就很快了。

然后就可以进行提问和对话了:

如果有兴趣继续探索的话,也可以安装个用户界面(现在这种是命令访问)。

Mac 用户可以安装 Enchanted APP:

Windows 用户可以参考这个:https://github.com/open-webui/open-webui 安装用户界面,较为复杂。不建议尝试。

使用 API 调用

Ollama 可以通过 API 进行调用,这也是我们可以在 Stata 中调用的原因。打开 Ollama 之后就可以使用类似下面的 curl 语句进行调用了(在 Stata 中可以使用 !curl 调用 curl):

!curl http://localhost:11434/api/generate -d '{"model": "deepseek-r1:1.5b", "prompt": "介绍一下微信公众号RStata", "stream": false}'

可以在结尾加上 -o temp.json 把输出的结果保存为 temp.json 文件:

!curl http://localhost:11434/api/generate -d '{"model": "deepseek-r1:1.5b", "prompt": "介绍一下微信公众号RStata", "stream": false}' -o temp.json

另外需要注意,在 Windows 电脑上,上述的 curl 语句需要进行如下调整:

  1. 单引号都要替换成双引号;
  2. 双引号都替换成 "。
!curl http://localhost:11434/api/generate -d "{\"model\": \"deepseek-r1:1.5b\", \"prompt\": \"介绍一下微信公众号RStata\", \"stream\": false}" -o temp.json

提取历年政府工作报告中的经济增长目标

由此我们便可以提取历年政府工作报告中的经济增长目标了。附件中的 78-24政府工作报告 存放了 1978~2024 年历年的政府工作报告 txt 文件。首先我们把这些 txt 文件读取到 Stata 中:

*- 读取政府工作报告文本
clear all
set maxvar 12000
set obs 47
gen year = 1977 + _n
gen content = ""
forval i = 1/`=_N' {
local temp = fileread("78-24政府工作报告/`=year[`i']'.txt")
replace content = `"`temp'"' in `i'
}

*- content 里面包含了换行符,我们可以把换行符替换成空白
gen temp = ustrregexs(0) if ustrregexm(content, "\n")
replace content = subinstr(content, temp, "", .)

*- 去除空格和双引号
replace content = subinstr(content, " ", "", .)
replace content = subinstr(content, `"""', "", .)
drop temp

save mydata, replace

读取到的结果是这样的:

为了方便进行类似的数据处理,我编写了一个 readfiles 命令。附件中提供了该命令的安装包:

readfiles 78-24政府工作报告, ext(txt) replace
gen year = ustrregexs(1) if ustrregexm(filename, "(\d{4})")
destring year, replace
drop filename
order year
save mydata, replace

测试一个年份的

我们先随便找一个年份的报告文本测试下效果:

use mydata, clear
*- 测试一个,每次解析 1000 个字
local temp = substr("`=content[20]'", 1, 3000)
!curl http://localhost:11434/api/generate -d '{"model": "deepseek-r1:1.5b", "prompt": "提取下面文本中的经济增长预期目标并以一个两列的markdown表格展示,一列是目标类型,一列是目标的值,不要显示无用信息:“`temp'”", "stream": false}' -o temp.json

虽然这里没有输入文本长度的限制,但是输入太长的文本会返回无意义的结果,所以每次我只处理 1000 个字(由于每个汉字在 Stata 中的长度是 3,所以这里是 3000)。再读取处理得到的结果:

insheetjson using "temp.json", showr flatten
clear all
gen str2045 response = ""
insheetjson response using "temp.json", columns("response")
replace response = ustrregexs(1) if ustrregexm(response, "\\u003c/think\\u003e(.*)")

更多关于 json 文件处理的内容可以学习这个课程:

Stata 网络数据爬取:JSON篇:https://rstata.duanshu.com/#/brief/course/c6de9fae65df4eeb814d2275545e224d

可以看到由于 str 字符串长度的限制,没有读取完整的 response 信息,所以我们这里就不适合使用 insheetjson 了,可以考虑把 json 文件作为普通文本进行处理:

clear all
set obs 1
local temp = fileread("temp.json")
gen response = `"`temp'"'
replace response = ustrregexs(1) if ustrregexm(response, `"\\u003c/think\\u003e(.*)","done""')

split response, parse("\n")
drop response
gather response*
drop if mi(value)
drop if !index(value, "|")
drop var
split value, parse("|")
drop value
drop value1
foreach i of varlist _all {
cap format `i' %10s
}

drop if index(value2, "---")
replace value2 = subinstr(value2, "*", "", .)
replace value2 = subinstr(value2, " ", "", .)
replace value3 = subinstr(value3, " ", "", .)

drop if value2 == "目标类型" | value2 == "类型"
drop if mi(value3) | value3 == "?"
ren value2 variable
ren value3 value

然后我们循环处理该年的整篇报告文档:

use mydata, clear
di strlen("`=content[20]'")
*> 46776
cap mkdir "res20"

forval i = 1(3000)`=strlen("`=content[20]'")' {
if !fileexists("res20/`i'.json") {
local temp = substr("`=content[20]'", `i', 3000)
!curl http://localhost:11434/api/generate -d '{"model": "deepseek-r1:1.5b", "prompt": "提取下面文本中的经济增长预期目标并以一个两列的markdown表格展示,一列是目标类型,一列是目标的值,不要显示无用信息:“`temp'”", "stream": false}' -o res20/`i'.json
}
}

这样所有的结果就都存放到 res20 文件夹里面了,再读取合并:

clear all
readfiles res20, ext(json) replace
save rawjsondata, replace

use rawjsondata, clear
ren content response
replace response = ustrregexs(1) if ustrregexm(response, `"\\u003c/think\\u003e(.*)","done""')

然后再稍加处理:

split response, parse("\n")
drop response
gather response*
drop if mi(value)
drop if !index(value, "|")
drop var
split value, parse("|")
drop value
drop value1
foreach i of varlist _all {
cap format `i' %10s
}

drop if index(value2, "---")
replace value2 = subinstr(value2, "*", "", .)
replace value2 = subinstr(value2, " ", "", .)
replace value3 = subinstr(value3, " ", "", .)
replace value2 = subinstr(value3, " ", "", .)
replace value3 = subinstr(value3, " ", "", .)

drop if value2 == "目标类型" | value2 == "类型"
drop if mi(value3) | value3 == "?" | value3 == "值"
ren value2 variable
ren value3 value

这样就提取到了所有的相关结果。

循环所有年份的

在此基础上再循环所有年份:

*- 此处代码需下载讲义查看~

这个过程可能会非常耗时,我用了一整夜才运行完。

然后合并所有的 json 文件:

clear all
readfiles res, ext(json) replace
save rawjsondataall, replace

再整理下:

*- 此处代码需下载讲义查看~

这样得到的是所有相关的结果,如果只想要经济增长率的目标,可以筛选下:

use tidydata, clear
keep if index(variable, "增长") & ustrregexm(variable, "(国民)|(经济)|(生产)|(GDP)")
drop if index(variable, "*")
keep if ustrregexm(value, "\d+")
gsort year
drop if ustrregexm(variable, "(能源)|(工业)|(农业)|(播种)")
save 待手动筛选, replace

不过看起来还需要后续的手动筛选。不过相信到这里也能节省不少工作量了。特别是要处理的文档特别多的时候。

点击这里跳转到 RStata 短书平台获取附件:使用 Stata 调用本地部署的大语言模型进行文本主要内容提取——历年政府工作报告中的经济增长目标提取(deepseek版本)

评论