哈喽,诸位爬友可安好?吾日三省吾身,数据爬取了乎?处理了乎?有啥要问爬小二的乎?日前一位爬友,来自江西财经大学的付童鞋在处理数据时候,遇到了一些obstacle,向爬小二求助,今天,我们就来解决这一问题。
问题是这样的:付童鞋想把下图中的数据按照stkcd(股票代码)和year(年份)拆分,并分别保存。如果数据量不大的话,重复几次keep if,save就可以了,但问题是:有近三千家公司、11年共一百多万条观测值(篇幅限制,只截取部分,见图1、图2),不可能手工一次次keep if & save,不然要累死洒家了。What shall we do?大家很容易就想到了循环。但问题又来了,按照stkcd循环,同时还要按照年份循环,并且股票代码那么多,还是重复的,怎么写循环呢?下面笔者就带着各位一层一层的剥开它的“心”,额。。。错了,是一层一层的冲破它的“壳”(由内向外)。
图1
图2
第一层
如果先按照一个stkcd和year拆分并保存的话(比如stkcd为1,year为2006),很容易想到用如下命令:
keep if stkcd ==1 & year == 2006 // 保留stkcd为1,且year为2006的数据
save 1_2006 // 保存数据文件,并命名为“1_2006”
这样就按照stkcd和year把股票代码为1且为2006年的数据拆分并保存下来。But,keep之后,只剩if条件下的这么一小点儿数据了,其他的被deleted掉了,怎么办?冲破第一层,向第二层前进。
第二层
在第一层中,我们成功的把股票代码为1且为2006年的数据拆分并保存下来,但其余数据被deleted掉了,我们无法继续保存其他股票代码和年份的数据了,为解决此问题,我们亮出preserve......restore这件“兵器”。李春涛教授曾经在讲该命令时,形象的把它称作“起死回生”命令。有了这个命令,失去的数据,我们就可以让它起死回生了。命令如下:
……
preserve // 保存preserve之前的数据,避免数据在程序执行后改变
keep if stkcd ==1 & year == 2006
save 1_2006
restore //数据还原,恢复到preserve之前的数据状态
用了这套“神器”之后,又恢复到原数据的状态,我们就可以继续keep if & save下一组数据了。but,another new problem is:股票代码近三千,且每个股票代码都有很多年份对应,一百多万条观测值,要是一次次的keep if & save的话……too horrible,算了,还是give up吧。且慢,都过两关了,兄弟挺住!别怕,来个循环压压惊!好嘛,这就迈向第三层。
第三层
由于这层壳有些厚,所以一次冲不破,那就反复多冲几回(循环)。stkcd和year哪个相对较薄一些,好冲呢?通过duplicates drop stkcd, force(删除重复值),我们发现stkcd有2968个,如下图(图3):
图3
看来,stkcd太多,不算重复的,也近三千,而且代码还不连续,有难度,再来看看year,见下图(图4):
图4
year太cool啦,不算重复的话,就11个,而且连续有规律,简直爽歪歪。柿子先挑软的捏,就先从year下手突破。year是从2006年到2016年循环,我们用forvalue循环,命令如下:
forv i =2006/2016 { // 若宏`i'取值从2006到2016,就执行{}中的命令,否则跳出循环
preserve // 将当前内存中数据暂封存,直到restore 命令再复原
keep if stkcd == 1 & year == `i' /* 保留stkcd为1,且year为2006年到2016年之间某年的数据 */
save 1_`i' // 保存数据文件,并命名为“1_年份”
restore // 数据还原,恢复到preserve之前的数据状态
}
至此,我们用forvalue循环语句,把股票代码为1的所有年份都循环拆分并保存下来。这层壳经过反复进攻,总算是冲破了,接下来就是把所有股票代码的所有年份都拆分并保存了,只要拿下所有股票代码,我们的任务就算完成了。但面临的是近三千的股票代码stkcd,怎么办?毫无疑问还是必须使用功能强大的循环命令嘛;那么具体我们怎么循环呢?下面进入第四层。
第四层
最后我们来啃这硬骨头。由于股票代码stkcd很多,而且有重复,我们当然可以先duplicates drop stkcd, force(删除重复值),提取出所有股票代码,然后恢复原数据状态,按照提取出的股票代码来做循环,但不够简捷。能用简单的程序解决同样的问题,那是我们推崇的。这里我们用一个简单的命令:levelsof来列出股票代码的值,并循环,命令如下:
levelsof stkcd,local(levels) /* 列出stkcd内不同数值,并将stkcd的值“放入”名为levels的局部宏里 */
foreach c of local levels { /* 用foreach循环语句,按局部宏levels 里的stkcd值进行循环 */
forv i = 2006/2016 { // 本行及以下命令参考第三层的命令注释
preserve
keep if stkcd == `c' & year == `i'
save `c'_`i'
restore
}
}
到这里,我们终于拿下了所有股票代码,并且正如江财付童鞋想要的那样,按照stkcd(股票代码)和year(年份)拆分、分别保存,并命名为“股票代码_年份”,我们截取一小块儿如下图(图5、图6):
图5
图6
一共有三万多个这样的dta文件,从凌晨0:29一直到凌晨3:19才结束,是不是很辛苦呢?没有啦,这些都是循环的功劳,它让计算机不停地干活,我们这时早已在梦乡:梦里仿佛已经嗅到了壳外的阳光,模糊看到了外面精彩的世界,我们即将破壳而出!突然,只听“裤裤擦擦”壳就裂了,“霹雳咔嚓”壳全开了,然后是千数万据成群结队,是“噗啦啦啦”滴破壳蹦出啊,风起云涌、尘土飞扬,排山倒海、地动山摇,惊天地、泣鬼神,声势浩大、蔚为壮观!……睡梦醒来,赶紧看看电脑吧,果然数万条数据从原dta文件破壳而出,齐刷刷的映入眼帘,终于破壳成功!开森地唱首歌庆祝胜利吧:一层又一层,一遍又一遍,功能强大的循环(请自行匹配歌曲“童年”的调子来唱,哈哈)~
最后我们把完整“破壳过程”呈现如下:
clear //清空内存
set more off // 设置屏幕滚动不停
use "D:\破壳.dta",clear //打开原数据文件"破壳.dta"
/* 下面嵌套循环程序各行命令注释见(1)—(4),这里不再赘述 */
levelsof stkcd,local(levels)
foreach c of local levels {
forv i = 2006/2016 {
preserve
keep if stkcd == `c' & year == `i'
save `c'_`i'
restore
}
}
今天就到这儿了,要想健康,常来逛逛,有事没事,爬爬更健康!去爬爬锻炼一下吧!
我是爬虫俱乐部爬小二,爬爬更健康!今天你爬了吗?爬爬是谁?下期见!
等等,我,爬小二又回来了,sorry,忘了告诉大家one important thing:
当你想对变量里的取值做循环时,下面这套组合非常实用:
levelsof factor,local(levels)
foreach var of local levels {
.......
}
有兴趣的同学可以help levelsof命令哦。
OK,see u tomorrow ,I am waiting for u in crawler club,bye~
我们团队原来的微信公众号是“数据处理援助中心”,现在正式搬家到“爬虫俱乐部”,欢迎关注。新的公众号开始,我们推出有问必答栏目,对您提出的问题,我们会尽力回答,并通过推文的形式进行发布。我们也欢迎各位粉丝向公众号投稿。
(编辑@付彩月)
欢迎大家踊跃投稿,介绍一些关于stata的数据处理和分析技巧。
投稿邮箱:xueyuan19920310@163.com
投稿要求:
1)必须原创,禁止抄袭;
2)必须准确,详细,有例子,有截图;
注意事项:
1)所有投稿都会经过本公众号运营团队成员的审核,审核通过才可录用,一经录用,会在该推文里为作者署名。
2)邮件请注明投稿,邮件名称为“投稿”+“推文名称”。
3)如果大家遇到关于stata处理分析数据的问题,也可以给该邮箱写邮件,邮件名称为“提问”+“问题名称或者关键词”,我们会在后期的推文里给予解答。
长按二维码关注哦
微信扫一扫
关注该公众号