“裤裤擦擦”“霹雳咔嚓”“噗啦啦啦”滴破壳

2016-10-11 赵磊 爬虫俱乐部 爬虫俱乐部

哈喽,诸位爬友可安好?吾日三省吾身,数据爬取了乎?处理了乎?有啥要问爬小二的乎?日前一位爬友,来自江西财经大学的付童鞋在处理数据时候,遇到了一些obstacle向爬小二求助,今天,我们就来解决这一问题。

问题是这样的:付童鞋想把下图中的数据按照stkcd(股票代码)和year(年份)拆分,并分别保存。如果数据量不大的话,重复几次keep ifsave就可以了,但问题是:有近三千家公司、11年共一百多万条观测值(篇幅限制,只截取部分,见图1、图2),不可能手工一次次keep if & save,不然要累死洒家了。What shall we do?大家很容易就想到了循环。但问题又来了,按照stkcd循环,同时还要按照年份循环,并且股票代码那么多,还是重复的,怎么写循环呢?下面笔者就带着各位一层一层的剥开它的,额。。。错了,是一层一层的冲破它的(由内向外)。


图1


图2

第一层

如果先按照一个stkcdyear拆分并保存的话(比如stkcd1year2006),很容易想到用如下命令:

       keep if stkcd ==1 & year == 2006       // 保留stkcd1,且year2006的数据

       save 1_2006       // 保存数据文件,并命名为“1_2006”

这样就按照stkcdyear把股票代码为1且为2006年的数据拆分并保存下来。Butkeep之后,只剩if条件下的这么一小点儿数据了,其他的被deleted掉了,怎么办?冲破第一层,向第二层前进。

第二层

在第一层中,我们成功的把股票代码为1且为2006年的数据拆分并保存下来,但其余数据被deleted掉了,我们无法继续保存其他股票代码和年份的数据了,为解决此问题,我们亮出preserve......restore这件兵器。李春涛教授曾经在讲该命令时,形象的把它称作起死回生命令。有了这个命令,失去的数据,我们就可以让它起死回生了。命令如下:

       ……

preserve       // 保存preserve之前的数据,避免数据在程序执行后改变

keep if stkcd ==1 & year == 2006

save 1_2006

restore       //数据还原,恢复到preserve之前的数据状态

用了这套神器之后,又恢复到原数据的状态,我们就可以继续keep if & save下一组数据了。butanother new problem is:股票代码近三千,且每个股票代码都有很多年份对应,一百多万条观测值,要是一次次的keep if & save的话……too horrible,算了,还是give up吧。且慢,都过两关了,兄弟挺住!别怕,来个循环压压惊!好嘛,这就迈向第三层。

第三层

由于这层壳有些厚,所以一次冲不破,那就反复多冲几回(循环)。stkcdyear哪个相对较薄一些,好冲呢?通过duplicates drop stkcd, force(删除重复值),我们发现stkcd2968个,如下图(图3):


图3

看来,stkcd太多,不算重复的,也近三千,而且代码还不连续,有难度,再来看看year,见下图(图4):


图4

yearcool啦,不算重复的话,就11个,而且连续有规律,简直爽歪歪。柿子先挑软的捏,就先从year下手突破。year是从2006年到2016年循环,我们用forvalue循环,命令如下:

forv i =2006/2016  {    // 若宏`i'取值从20062016,就执行{}中的命令,否则跳出循环

       preserve       // 将当前内存中数据暂封存,直到restore 命令再复原

       keep if stkcd == 1 & year == `i'    /* 保留stkcd1,且year2006年到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命令哦。

 OKsee u tomorrow I am waiting for u in crawler clubbye~

我们团队原来的微信公众号是“数据处理援助中心”,现在正式搬家到“爬虫俱乐部”,欢迎关注。新的公众号开始,我们推出有问必答栏目,对您提出的问题,我们会尽力回答,并通过推文的形式进行发布。我们也欢迎各位粉丝向公众号投稿。

(编辑@付彩月)

欢迎大家踊跃投稿,介绍一些关于stata的数据处理和分析技巧。

投稿邮箱:xueyuan19920310@163.com

投稿要求:

1)必须原创,禁止抄袭;

2)必须准确,详细,有例子,有截图;

注意事项:

1)所有投稿都会经过本公众号运营团队成员的审核,审核通过才可录用,一经录用,会在该推文里为作者署名。

2)邮件请注明投稿,邮件名称为“投稿”+“推文名称”。

3)如果大家遇到关于stata处理分析数据的问题,也可以给该邮箱写邮件,邮件名称为“提问”+“问题名称或者关键词”,我们会在后期的推文里给予解答。


长按二维码关注哦


微信扫一扫
关注该公众号