赶尽杀绝:Stata中文乱码之转码

发布时间:2020-03-05 阅读 134

作者:王美庭 (中南民族大学经济学院)

Stata连享会   主页 || 视频 || 推文

连享会 - Stata 暑期班

线上直播 9 天:2020.7.28-8.7
主讲嘉宾:连玉君 (中山大学) | 江艇 (中国人民大学)
课程主页https://gitee.com/arlionn/PX | 微信版
助教招聘: 15 名,免费听课,详见课程主页

连享会 - 文本分析与爬虫 - 专题视频

主讲嘉宾:司继春 || 游万海

连享会-文本分析与爬虫-专题视频教程
连享会-文本分析与爬虫-专题视频教程

目录


本文的目的: 当 Stata 官方提供的 unicode * 命令组和 连老师提供的 ua 命令执行完后仍然存在乱码时,可以试试本文的解决方案。本文的主要代码来自于「爬虫俱乐部 精通Stata之数据整理」,在其基础上进行了一些改进 (详情参见本文第三部分),主要包括两个方面:其一,可以对「数字-文字对应表」中的中文乱码进行自动转码。其二,支持批量多文件(夹)转码。

1. 问题阐述

时至今日,Stata 已经进入 16 时代代,各项功能日益完善。然而,对于广大中文老用户而言,仍然存在一个历史性问题——转码

这一切来源于 Stata 14 跨时代地全面启用了适用性更广的 UTF-8 编码格式,从而保证我们的 dofile.dta, .hlp 等文件中可以支持各种语言和字符,非英语用户再也不用一定使用英语字母作为变量名了。

历史遗留问题在于,对于国内用户,使用 Stata 13 及早期版本保存的 do 文件和 .dta 文件一般为 gb2312gbkgb18030 编码,而 Stata 14 及高级版本采用的是 UTF-8 编码。就像英文单词 he,在英语里的意思是他、男性,男子;雄性动物,而在汉语拼音中,可能被认为是和、何、禾等,所以同样的文字,在不同的编码下,将有不同的含义。于是,国内用户早期版本 Stata 保存下来的 do 文件和 .dta 文件在高级版本 Stata 下那些非英文字符出现乱码也是自然而然的事。

Stata 官方和用户们都给出了一些解决方案。比如,针对国内用户,官方提供了 unicode encoding set gb18030unicode translate * 命令组,以便实现转码 (从编码 gb18030 转码至 UTF-8 ) 命令,以及连玉君老师编写的 ua 命令对其的扩展(这里要注意的是,由于 gb18030 编码包含 gbk ,而 gbk 又包括 gb2312,所以针对国内用户,转码前设置编码 gb18030 即可)。

然而,当文件中包含了不可转换字符,则会导致以上命令无法奏效。当然,我们也可以加上 invalid 选项以保证上述命令被强制执行,但这样很可能会导致数据的部分位置被修改(而我们又不知道哪里被修改了),从而对后期的数据分析产生影响。

2. 解决方案

对于以上问题,在这里我们是怎么处理的呢?

对于 do 文件,处理还是比较简单的,我们在后期版本中打开时软件会自动提示选择何种编码打开,此时我们国内一般选择 gb18030 即可。本文重点在于解决 .dta 文件的转码。我们知道,.dta 文件的乱码一般会出现在数据标签、变量名、变量内容、变量标签、值标签。因此,对于每一个 .dta 文件,我们只需对这些部分利用相关的转码函数进行转码即可。这里看似与官方命令重复了,其实重要区别是如果 .dta 存在不可转换的字符,利用本文的做法,你就能发现不可转换的字符存在何处,然后通过本身对于数据的现有信息,手动更正即可(而对于官方命令,你不知道这里无法转换的字符在何处)。

我们最终的目的在于对于当前文件夹、子文件夹、子子文件夹中的所有 .dta 文件进行转码(由 gb18030 转至 UTF-8 ),如果刚开始就按照这个思维去写程序,这是比较困难的。我们先从单个文件入手,再进入单个文件夹,最后再对三层嵌套文件夹进行操作。

连享会计量方法专题……

2.1 转码程序——单个 .dta 文件

使用说明

这里的目的在于将单个 .dta 文件由 gb18030 编码转换至 UTF-8 编码。前面已经说过,.dta 文件可能出现乱码的地方有:数据标签、变量名、变量内容、变量标签、值标签。因此我们用 Stata 对这些可能出现乱码的地方依次进行转码,最后再将转码后的数据替换原来的数据,以防万一,以下程序还备份了原来的 .dta 文件。

具体的注意事项如下:

  1. 在当前目录下生成了 backup files 子文件夹。
  2. 将原 .dta 数据保存至了 backup files 子文件夹中。
  3. 转码后 UTF-8 格式的 .dta 数据,覆盖了当前文件夹的原数据。
  4. 此程序 只能转一遍,只能转一遍,只能转一遍!否则原数据将丢失,且数据重新变回乱码。
  5. 转换后若还存在乱码(一般只有少数),则这些乱码就是所谓的利用官方命令(unicode translate *)无法转换的字符,需要加 invalid 选项才能继续运行命令,但这样将造成数据被更改和丢失。而在这里,运行以下程序后数据本身并没有发生变化(只是编码发生了变化),而且我们还能定位到发生乱码的具体位置,接着我们只需要根据数据本身的信息(如调查问卷的阐述)对其中存在的少量的乱码进行手动修改即可,以保证数据的原始性
  6. 程序有“用户修改部分”和“无需变更部分”,顾名思义,用户只需在“用户修改部分”修改少量的程序,即可把以下代码用在自己的数据中。
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
*---------------------------用户修改部分---------------------------------------cd "D:\stata15\ado\personal\Net_course\"local dta_file "gdpChina.dta"

*----------------------------无需变更部分--------------------------------------use `dta_file', clear
*将原dta文件备份至"backup files"文件夹中cap mkdir "backup files"copy `dta_file' "backup files\", replace
*对数据标签进行转码local data_lbl: data labellocal data_lbl = ustrfrom("`data_lbl'", "gb18030", 1)label data "`data_lbl'"
*对变量名、变量标签、字符型变量取值转码foreach v of varlist _all { * 对字符型变量取值进行转码 local type: type `v' //将变量的类型放入宏type中 if strpos("`type'", "str") { replace `v' = ustrfrom(`v', "gb18030", 1) //如果变量是字符型变量,使用ustrfrom()函数进行转码 }
* 对变量标签进行转码 local lbl: var label `v' //将变量的标签放入宏lbl中 local lbl = ustrfrom("`lbl'", "gb18030", 1) //使用ustrfrom()函数对`lbl'转码 label var `v' `"`lbl'"' //将转码后的字符串作为变量的标签
* 对变量名进行转码 local newname = ustrfrom(`"`v'"', "gb18030", 1) //使用ustrfrom()函数将变量名字符串进行转码 qui rename `v' `newname' //将转码后的字符串重命名为变量名}
*下面对数值标签进行转码qui label save using label.do, replace //将数值标签的程序保存到label.do中(如果原来dta数据是gb18030编码,则这里导出的do文件也是gb18030编码)preserve //将do文件的内容用txt的方式导入一个变量之中qui import delimited using label.do, /// varnames(nonames) delimiters("asf:d5f14d5d",asstring) encoding(gb18030) clearqui describeif r(N) == 0 { restore save `dta_file', replace } else { qui levelsof v1, local(v1_lev) restore foreach label_modify of local v1_lev { //这个的foreach与前面的local(v_lev)对应,细节可查看帮助文件 `label_modify' //依次对原数据执行值标签替换操作 } save `dta_file', replace //将转码好的dta文件替换原来的dta文件 } * 删除中间临时文件erase label.do

2.2 转码程序——单个文件夹中的所有 .dta 文件

使用说明

这里的目的在于,将单个文件夹的所有 .dta 文件由 gb18030 编码转换至 UTF-8 编码。

具体的注意事项同 2.1 节一样。

  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line

*------------------------用户修改部分--------------------------------// cd "D:\stata15\ado\personal\Net_course"

*-------------------------无需变更部分--------------------------------local dir_dta: dir . files "*.dta", respectcase //windows系统需要加respectcase选项以区分大小写
cap mkdir "backup files" //建立备份文件夹foreach dta_file of local dir_dta { qui copy `dta_file' "backup files\", replace //将当前文件夹的dta数据备份至"backup files"文件夹中 qui use `dta_file', clear *对数据标签进行转码 local data_lbl: data label local data_lbl = ustrfrom("`data_lbl'", "gb18030", 1) label data "`data_lbl'" *对变量名、变量标签、字符型变量取值转码 foreach v of varlist _all { * 对字符型变量取值进行转码 local type: type `v' //将变量的类型放入宏type中 if strpos("`type'", "str") { replace `v' = ustrfrom(`v', "gb18030", 1) //如果变量是字符型变量,使用ustrfrom()函数进行转码 } * 对变量标签进行转码 local lbl: var label `v' //将变量的标签放入宏lbl中 local lbl = ustrfrom("`lbl'", "gb18030", 1) //使用ustrfrom()函数对`lbl'转码 label var `v' `"`lbl'"' //将转码后的字符串作为变量的标签 * 对变量名进行转码 local newname = ustrfrom(`"`v'"', "gb18030", 1) //使用ustrfrom()函数将变量名字符串进行转码 qui rename `v' `newname' //将转码后的字符串重命名为变量名 }
*下面对数值标签进行转码 qui label save using label.do, replace //将数值标签的程序保存到label.do中 preserve *- 将do文件的内容用txt的方式导入一个变量之中,然后再对该变量进行拉直 qui import delimited using label.do, /// varnames(nonames) delimiters("asf:d5f15g4dsf9qw8d4d5d",asstring) encoding(gb18030) clear qui describe if r(N) == 0 { restore save `dta_file', replace } else { qui levelsof v1, local(v1_lev) restore foreach label_modify of local v1_lev { //这个的foreach与前面的local(v_lev)对应,细节可查看帮助文件 `label_modify' //依次对原数据执行值标签替换操作 } save `dta_file', replace //将转码好的dta文件替换原来的dta文件 } * 删除中间临时文件 erase label.do}

连享会计量方法专题……

2.3 转码程序——三层嵌套文件夹下的所有 .dta 文件

使用说明

这里的目的在于,将当前文件夹、所有子文件夹、以及所有子子文件夹下的所有 .dta 文件由 gb18030 编码转换至 UTF-8 编码。

具体的注意事项除了 2.1 节的以外,其他的还有:

  1. 这部分程序嵌套了转码_单个文件夹.do文件(为了程序结构的易读性),于是用户在使用这部分程序之前,需要将 2.2 节的代码部分打包成转码_单个文件夹.do文件(内容无需更改,直接复制粘贴即可),然后将其放在D盘根目录下。
  2. 在“用户修改部分”将路径修改为自己要转码的路径即可。
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
*------------------------用户修改部分--------------------------------cd "D:\stata15\ado\personal\Net_course"

*-------------------------无需变更部分--------------------------------*将当前文件夹下的所有dta文件进行转码(第一层)do "D:\转码_单个文件夹.do"
*将当前子文件夹下的所有dta文件进行转码(第二层)local dir_list : dir . dirs "*", respectcaseforeach subdir of local dir_list { if "`subdir'" == "backup files" { continue //保留备份的原文件不动 } cd "`subdir'" do "D:\转码_单个文件夹.do" *将当前子子文件夹下的所有dta文件进行转码(第三层) local dir_list2 : dir . dirs "*", respectcase foreach subdir2 of local dir_list2 { if "`subdir2'" == "backup files" { continue //保留备份的原文件不动 } cd "`subdir2'" do "D:\转码_单个文件夹.do" qui cd .. } qui cd .. }

3. 引用说明

这里先表示一下谢意,文中引用了部分代码却没有做一个说明。同时在这里也先感谢原作者(爬虫俱乐部),正是你们的代码,给了本文以灵感。

下面进入正题:以上程序中部分代码借鉴了 「爬虫俱乐部-精通Stata之数据整理」 腾讯课程。这里将其原代码列示如下:

  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
* 构造数据clearcd "E:\直播课程\转码\ustrfrom"set obs 2gen _变量1 = "爬虫俱乐部" in 1replace _变量1 = "将爬虫进行到底" in 2   //变量名与字符型变量的取值gen v = _nlabel var v "标签变量"   //变量标签label define vlab 1 "是" 2 "否"   //值标签label values v vlab* 构造的数据中,变量名、字符型变量的取值、变量标签、值标签中都出现了中文,保存成gb18030编码后,都会成为乱码saveascii 转码.dta, replace encoding(gb18030) version(13)
* 转码use 转码.dta, clearforeach v of varlist _all { * 对字符型变量取值进行转码 local type: type `v' //将变量的类型放入宏type中 if index("`type'", "str") { replace `v' = ustrfrom(`v', "gb18030", 1) //如果变量是字符型变量,使用ustrfrom()函数进行转码 }
* 对变量标签进行转码 local lbl: var label `v' //将变量的标签放入宏lbl中 local lbl = ustrfrom("`lbl'", "gb18030", 1) //使用ustrfrom()函数对`lbl'转码 label var `v' `"`lbl'"' //将转码后的字符串作为变量的标签
* 对变量名进行转码 local newname = ustrfrom(`"`v'"', "gb18030", 1) //使用ustrfrom()函数将变量名字符串进行转码 rename `v' `newname' //将转码后的字符串重命名为变量名}* 变量名、变量标签、字符型变量的取值都转码完成,乱码还剩下数值标签label save using label.do, replace //将数值标签的程序保存到label.do中*****将label.do打开,将程序复制过来*****label define vlab 1 `"是"', modifylabel define vlab 2 `"否"', modify********这段程序将对数值标签转码************************转码完成****************

对于以上代码,本文的改进之处如下:

  • 改进1: 可以支持对「数字-文字对应表」中的中文乱码进行转码。 爬虫俱乐部提供的代码重点解决了 .dta 数据文件中 变量名、变量内容、变量标签、数字-文字对应表 可能存在的乱码,事实上,数据标签 (Stata 中的定义方式为 label data "xxx") 也可能存在乱码,在使用一份数据之前,能够提前知道其大致的内容是很重要的,而 数据标签 就起着这样的功能。
  • 改进2:自动对 .dta 文件中「数字-文字对应表」中的中文标签进行转码:原代码需要手动复制粘贴,操作上繁复且易出错。经本文测试,.do 文件可以用 import delimited 导入,再通过一系列的判断语句和循环语句,真正实现自动化一次性转码完成。
  • 改进3: 支持批量多文件(夹)转码。 原代码只针对单个文件进行转码,本文方法不仅可以针对单个文件,而且可以对当前目录的所有 .dta 文件、当前目前目录下子文件夹下的所有 .dta 文件以及子子文件夹(三层嵌套)下的所有 .dta 文件进行一次性转码**。

附录

以上三部分代码的Stata do文件如下:

   

相关课程

连享会-直播课 上线了!
http://lianxh.duanshu.com

免费公开课:


课程一览

支持回看,所有课程可以随时购买观看。

专题 嘉宾 直播/回看视频
Stata暑期班 连玉君
江艇
线上直播 9 天
2020.7.28-8.7
效率分析-专题 连玉君
鲁晓东
张 宁
视频-TFP-SFA-DEA
已上线,3天
文本分析/爬虫 游万海
司继春
视频-文本分析与爬虫
已上线,4天
空间计量系列 范巧 空间全局模型, 空间权重矩阵
空间动态面板, 空间DID
研究设计 连玉君 我的特斯拉-实证研究设计-幻灯片-
面板模型 连玉君 动态面板模型-幻灯片-
直击面板数据模型 [免费公开课,2小时]

Note: 部分课程的资料,PPT 等可以前往 连享会-直播课 主页查看,下载。


关于我们

  • Stata连享会 由中山大学连玉君老师团队创办,定期分享实证分析经验。直播间 有很多视频课程,可以随时观看。
  • 连享会-主页知乎专栏,300+ 推文,实证分析不再抓狂。
  • 公众号推文分类: 计量专题 | 分类推文 | 资源工具。推文分成 内生性 | 空间计量 | 时序面板 | 结果输出 | 交乘调节 五类,主流方法介绍一目了然:DID, RDD, IV, GMM, FE, Probit 等。
  • 公众号关键词搜索/回复 功能已经上线。大家可以在公众号左下角点击键盘图标,输入简要关键词,以便快速呈现历史推文,获取工具软件和数据下载。常见关键词:
    • 课程, 直播, 视频, 客服, 模型设定, 研究设计, 暑期班
    • stata, plus,Profile, 手册, SJ, 外部命令, profile, mata, 绘图, 编程, 数据, 可视化
    • DID,RDD, PSM,IV,DID, DDD, 合成控制法,内生性, 事件研究, 交乘, 平方项, 缺失值, 离群值, 缩尾, R2, 乱码, 结果
    • Probit, Logit, tobit, MLE, GMM, DEA, Bootstrap, bs, MC, TFP, 面板, 直击面板数据, 动态面板, VAR, 生存分析, 分位数
    • 空间, 空间计量, 连老师, 直播, 爬虫, 文本, 正则, python
    • Markdown, Markdown幻灯片, marp, 工具, 软件, Sai2, gInk, Annotator, 手写批注, 盈余管理, 特斯拉, 甲壳虫, 论文重现, 易懂教程, 码云, 教程, 知乎

连享会主页  lianxh.cn
连享会主页 lianxh.cn

连享会小程序:扫一扫,看推文,看视频……


扫码加入连享会微信群,提问交流更方便

✏ 连享会学习群-常见问题解答汇总:
https://gitee.com/arlionn/WD