赞
踩
Stata 中经常需要对 字符变量
做处理,将 字符变量
转换为 数值变量
。但 字符变量
的形式多样,包括 标识符变量/分类变量
、日期变量
、纯数字变量
等,在转换过程中需要使用不同的转换方法。尤其当字符串内容为数字时(如 日期变量
、纯数字变量
),需要格外小心。
本篇推文将提供七个建议,涵盖多种字符串形式的处理方法,帮助大家更好的处理字符型变量。
save
命令将修改后的数据另存为新的
.dta 文件,不要直接修改替换原始数据。
import
)数据的任何原始数据文件,例如文本或电子表格文件。有时,可能需要返回到源头并重新开始数据导入和处理工作。
因为字符串转换很容易出错,所以在字符串操作过程中,通常生成一个新的变量来保存转换结果,而不是替换原有的字符串变量。有些命令提供 replace
选项,可以将原始变量替换为转换后的结果,但这种情况下,如果转换出错将找不到原始的字符串变量。更好的方式是使用 generate()
选项生成新的变量,如果出现错误,也可以回到原始变量,重新修改。
译者注: 需要补充说明的是,如果遵循了第一条建议,即我们的 do 文档 的首行始终是以 import xxx.txt
或 import xxx.xlsx
的方式导入原始 TXT 或 Excel 文档,那么可以在 dofile 中采用 replace
的方式替换到原变量,以免产生过多的新变量。后续处理过程中若需返回,则可以重新导入原始数据。
使用 list
、edit
或 browse
命令查看字符串变量,如果变量中包含形如 20jan2010 09:15:22
、20/01/2010
、2010w3
、2010q1
的数据,这种变量就是**“日期型”**字符串变量,通常包含以下几种类型:
日期类型 | 该类型的显示格式 |
---|---|
datetime | 20jan2010 09:15:22.120 |
(daily) date | 20jan2010, 20/01/2010, ... |
weekly date | 2010w3 |
monthly date | 2010m1 |
quarterly date | 2010q1 |
half-yearly date | 2010h1 |
yearly date | 2010 |
如果日期型变量是以字符串保存的形如 1984
或 2018
这样的年度日期,可以直接使用 destring
命令转换为数值格式,具体见 help destring
。
如果字符串变量包含日期或时间,需要使用日期-时间函数转换为数字格式的日期或时间变量。具体转换过程可以分为如下两个步骤: Step 1: 使用日期-时间函数 help datetime
,将字符串日期转换为数字日期 Step 2: 使用 format
命令,将数字显示为想要的日期格式
数字日期,可以理解为某一日期距离原点的时间间隔。Stata 将 1960 年的第一个日期设为原点 0(如:日度数据的原点为 1960年1月1日
;月度数据的原点为 1960 年第 1 月
;周数据的原点为 1960 年第 1 周
)。不同的日期类型,计算时间间隔的单位不同(如:日度数据为 间隔天数
,月度数据为 间隔月数
,周数据为 间隔周数
)。
以日度数据为例,1776年7月4日
的数字日期是 -67019
,表示 1960年1月1日
之前的第67019
天。从这里可以看出一个问题:对于字符串日期来说,含义是很直观的;但对于数字日期,含义通常比较模糊(如 67019
),很难直观判断这个数字代表的是什么日期。可以通过 format
命令,将数字日期显示为日期格式,详情参见 help format
。
format
的语法为 format varlist %fmt
,其中 varlist
为数字日期变量,%fmt
为显示的日期格式,需要与日期类型相对应(如:日度数据的日期格式为 %td
)。常见的日期类型与对应的日期显示格式如下表所示:
日期格式 %fmt | 日期类型 | 举例 |
---|---|---|
%tc | date/time | format varlist %tc |
%tC | date/time | format varlist %tC |
%td | date | format varlist %td |
%tw | week | format varlist %tw |
%tm | month | format varlist %tm |
%tq | quarter | format varlist %tq |
%th | half-year | format varlist %th |
%ty | year | format varlist %ty |
%tg | generic | format varlist %tg |
日期-时间函数 的功能是将文本日期转换为数字日期,可以通过 help datetime
查找。具体使用哪一个函数,根据字符串变量的日期类型确定。比如对于日度数据 20jan2010
,可以使用 date() 或者 daily()
函数。(这两个函数的功能是一样的,但 daily()
的函数名更直观,所以推荐使用 daily()
函数。)
举个简单的例子:
. clear
. set obs 1
. gen strDate = "July 4, 1776" //生成“日期型”字符串变量
*-(一)根据日期函数 daily(),
strDate numDate |
---|
*-(二)设定数字日期(numDate)的显示格式
. format numDate %td
. list
±-------------------------+
| strDate numDate |
|--------------------------|
上述代码中,daily()
函数将字符串日期 "July 4, 1776"
转换成数字日期 -67019
,这个数值是 "1776年7月4日"
距离原点 "1960年1月1日"
的天数。format
命令将数字日期 -67019
显示为日度数据格式 04jul1776
。
(1)对于字符串形式的季度数据 "2018q1"、"2018q2"
,可以通过 quarterly()
函数转换为数字形式的季度数据。
(一)生成字符串形式的季度数据
. clear
. set obs 2
. input str20 date
date
1. "2018q1"
2. "2018q2"
(二)将字符串形式的季度数据(date)转换为 数字形式的季度数据(numdate)
. gen numdate = quarterly(date, “YQ”)
. format numdate %tq
. list
±-----------------+
| date numdate |
|------------------|
(2)如果用每一季度的最后一天(日度数据形式)来表示季度数据,如 "2018-3-31"、"2018-6-30"
,如何将字符串转换为数字形式的季度数据格式(2018q1、2018q2
)? help datetime
可以找到不同类型的数字日期之间的转换函数,其中 qofd()
函数可以将数字形式的日度数据转换为数字形式的季度数据,结合 daily()
函数,可以很好的解决上述问题。
解决方案: qofd(daily())
,具体实现过程如下:
* (一)生成日度数据形式的季度数据
. clear
. set obs 2
. input str20 date
date
1. "2018-3-31"
2. "2018-6-30"
(2)将数字形式的日度数据(daily)转换为数字形式的季度数据(quarter)
. gen daily = daily(date, “YMD”)
. gen quarter = qofd(daily)
. list
±----------------------------+
| date daily quarter |
|-----------------------------|
date daily quarter |
---|
1. |
2. |
对于标识符变量(如:公司、国家、地区名称)或者分类变量,可以通过 (1)encode命令
;(2)egen 命令的 group() 函数
两种方式,将字符变量映射到数字变量。
在开始之前,我们生成一个分类变量,用以详细说明两种命令的使用方式:
// 生成一个 yesno 变量,保存为 yesno.dta 数据。
// yesno 是一个分类变量,包括三个取值(yes,no,Dont know)
clear
set obs 3
input str20 yesno
"Yes"
"No"
"Dont know"
save yesno.dta, replace
encode
命令默认情况下,Stata 中的 encode
命令会将字符变量按字母排序。字符变量的不同取值,按照排列顺序分别映射到数值 1,2,...
,并且为生成的数字变量添加值标签,用以说明字符串-数字的对应关系。
encode
命令的语法为:
encode varname [if] [in], generate(newvar) [label(name)]
其中 varname
为需要转换为数字的分类/标识符变量;选项 generate(newvar)
表示生成新的变量(newvar
)存储转换后的结果;选项 label(name)
表示按照变量值标签(name
)中的“字符串-数字”的对应关系来转换(默认按照字母排序转换)。
* (一)查看数据:变量 yesno 中包括三个取值("Yes", "No", "Dont know")
. use yesno.dta, clear
. list
+-----------+
| yesno |
|-----------|
1. | Yes |
2. | No |
3. | Dont know |
+-----------+
(二)生成两个变量值标签(yesno1, yesno2)
. label define yesno1 1 “Yes” 2 “No” 3 “Don’t know”
. label define yesno2 1 “Yes” 2 “No” 3 “Dont know”
. label list
yesno2:
1 Yes
2 No
3 Dont know
yesno1:
1 Yes
2 No
3 Don’t know
(三)将字符变量 yesno 转换为数值变量
. encode yesno, gen(newvar) //按默认排序(字母顺序)转换
. encode yesno, gen(newvar1) label(yesno1) //按值标签 yesno1的“字符串-数字”对应关系转换
. encode yesno, gen(newvar2) label(yesno2) //按值标签 yesno2的“字符串-数字”对应关系转换
. label list
yesno1:
1 Yes
2 No
3 Don’t know
4 Dont know
newvar:
1 Dont know
2 No
3 Yes
yesno2:
1 Yes
2 No
3 Dont know
. list, nolab //生成的三个转换变量的数字取值情况
±---------------------------------------+
| yesno newvar newvar1 newvar2 |
|----------------------------------------|
. list //显示三个转换变量的值标签
±----------------------------------------------+
| yesno newvar newvar1 newvar2 |
|-----------------------------------------------|
可以看出,当使用值标签 yesno1
时,由于值标签中没有 dont know
的数字对应关系,Stata 会自动在值标签后面追加一个数字,作为 dont know
字符串的映射。
egen 的 group() 函数
egen
命令的 group()
函数可以起到同样的效果: egen newvar = group(varname), label
,其中 varname
为标识符/分类变量,newvar
为生成的数值变量,选项 label
表示按字母顺序添加值标签(默认情况下不添加值标签)。
. use yesno.dta, clear
. egen b = group(yesno)
. egen b1 = group(yesno), label
. label list
b1:
1 Dont know
2 No
3 Yes
. list, nolab
±-------------------+
| yesno b b1 |
|--------------------|
yesno b b1 |
---|
如果字符串中存在多余的空格,比如 "I Love Python"
," I Love Python"
,"I Love Python "
," I Love Python"
,Stata 会认为这是四个不同的字符串,转换为数字变量的时候,也会对应到四个不同的数字。在处理这类问题的时候,通常使用 trim()
itrim()
函数,去掉字符串两端的空格,或者规范字符串内部的空格,将上述四个字符串处理成相同的字符串 "I Love Python"
。具体详见 help string functions
。
有些字符串变量可以保留为字符串形式,没必要转换成数字格式。比如:
数据中可能包含一些与数据的定义、解释、注释相关的信息(元数据),这类信息可以作为变量名称、变量标签、值标签或注释等反映到数据中。有时元数据也会解释缺失值或异常值的产生原因及编码方式,这些文字说明很有用,但这些文字并不需要全部包含在数据集中。
Stata 并不能识别哪些文字是说明性的文字,不需要读入;哪些文字是数据的一部分,需要以数据形式读入;哪些文字可以作为变量名或者变量标签。如果直接使用 import
命令,Stata 会将所有文本全部导入数据中,生成很多的字符变量来存储元数据中的文字信息。但很多时候并不需要这些元数据,或者有些元数据仅需要作为变量名称、变量标签,此时需要从导入的数据中删除或者处理元数据信息。
针对元数据信息,通常有两种处理方式: (1)如果已经导入了元数据,可以根据具体情况,删除不需要的元数据所在的行;使用 destring
命令将元数据导致的字符变量转换为数字变量。 (2)重新导入数据(import excel
、import delimited
),使用 import
命令提供的选项,可以跳过数据文件中元数据所在的行和列,也可以将首行内容作为变量标签或者变量名。
destring
命令字符串变量主要可以分为 “日期型”字符变量、“标识变量/分类变量”、由于元数据的存在导致的字符变量。对于“日期型”字符变量,使用日期-时间函数 help datetime
转换为数值变量;对于“标识变量/分类变量”,使用 encode varname
、egen newvar = group(varname)
两种方式编码为数值变量;如果是元数据造成的字符变量,通过 import 选项
或者 drop 元数据所在行
来删除元数据。
若逐个排除了上述过程,剩下的字符变量通常可以使用 destring
来转换为数值变量。Stata 会以数字格式读入纯数字变量,但如果变量中包含非数字内容(如将 110
误写为 11o
),或者受到了元数据污染(如:数字变量的最后几行写了一些注释信息),则这些纯数字内容会以字符串的形式导入数据,形成字符变量。当删除元数据以后,纯数字形成的字符变量可以使用 destring
命令转换为数值变量。
destring
命令有点类似于 real()
函数,可以将字符串形式的数字转换成数值形式的数字,但 destring
更灵活的地方在于提供了很多选项,可以处理字符变量中的非数字形式的字符,比较常用的几个选项包括 force
、ignore()
、percent
、dpcomma
。
force
选项将纯数字字符转换成数字,同时强制将无法识别的字符处理成缺失值,是不得已情况下才会使用的选项;ignore("chars")
选项去除字符中的 "chars"
字符,将剩余的内容转换为数字。percent
选项将数字字符串转换成小数形式;dpcomma
选项将字符中的逗号作为小数点转换为十进制格式(如 "12,3"
转换为 12.3
)。
我们生成一个字符串变量,用来详细介绍各个选项的用途。
// 生成字符串变量
clear
set obs 7
input str20 whatever
"209"
"1560"
"52o"
"ll9"
"NA"
"12,3"
"79%"
save temp.dta, replace
各选项的使用方法和结果如下:
. // force 选项
. use temp.dta, clear
. destring whatever, generate(wanted) force
. list, sep(0)
+-------------------+
| whatever wanted |
|-------------------|
1. | 209 209 |
2. | 1560 1560 |
3. | 52o . |
4. | ll9 . |
5. | NA . |
6. | 12,3 . |
7. | 79% . |
+-------------------+
. //ignore 选项
. use temp.dta, clear
. destring whatever, generate(wanted) ignore(“NA%ol,”)
. list, sep(0)
±------------------+
| whatever wanted |
|-------------------|
. //dpcomma 选项
. use temp.dta, clear
. destring whatever, generate(wanted) ignore(“NAlo%”) dpcomma
. list, sep(0)
±------------------+
| whatever wanted |
|-------------------|
. //percent 选项
. use temp.dta, clear
. destring whatever, generate(wanted) ignore(“NAlo”) percent dpcomma
. list, sep(0)
±------------------+
| whatever wanted |
|-------------------|
destring
可以将纯数字的字符串转换成数字格式,如果变量中包含某些特殊字符(如输入错误: 52o
;缺失值:NA
;百分号:%
),我们需要使用 destring
的选项来处理这些特殊字符。为了更好的使用 destring
选项,我们希望查看 destring
无法自动处理的内容。
具体查看命令:tabulate whatever if missing(real(whatever))
,其中 whatever
为需要转换成数字的字符串变量。
// 原始数据中包含一个变量:whatever
. use temp.dta, clear
. list, sep(0)
+----------+
| whatever |
|----------|
1. | 209 |
2. | 1560 |
3. | 52o |
4. | ll9 |
5. | NA |
6. | 12,3 |
7. | 79% |
+----------+
// 打印 destring 无法转换的内容
. tabulate whatever if missing(real(whatever))
whatever | Freq. Percent Cum.
---------------------±----------------------------------
12,3 | 1 20.00 20.00
52o | 1 20.00 40.00
79% | 1 20.00 60.00
NA | 1 20.00 80.00
ll9 | 1 20.00 100.00
---------------------±----------------------------------
Total | 5 100.00
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。