在进行数据探索之前,笔者将首先加载需要用到的R包,具体代码如下:
> library(data.table) # fread() > library(tidyverse) # ggplot()
接着,笔者将数据读取到Rstudio环境中。这里使用了data.table包中的fread函数读取数据。fread函数是目前R中读取平面文档速度最快、功能最强的数据导入函数。需要注意的是,文件路径需要根据读者的个人设置来重新指定。读取完成后使用dim函数来快速检索数据集,str函数也同样适用。示例代码具体如下:
> responses <- fread("./multipleChoiceResponses") > dim(responses) ## [1] 15859 228
之所以使用dim函数,是因为数据集略大,即便显示部分也会占据很大篇幅。笔者仅对部分变量进行处理分析,下一步需要快速选择出相关的变量。这里可供读者选择的方式有很多种,比如dplyr包中的select,data.table包中设置位置j(参见第6章的讲解)等。这里选择data.table包中的方式。提醒使用Rstudio的读者注意使用Tab键配合变量的选择,一般情况下,读者仅需要输入1到2个字母之后使用Tab键,Rstudio便会给出选择清单。示例代码具体如下:
> responses <- responses[,.(Age,Country,CurrentJobTitleSelect,MLToolNextYearSelect,MLMethodNextYearSelect,EmploymentStatus, FormalEducation,CoursePlatformSelect,FirstTrainingSelect,Tenure,JobSatisfaction,LanguageRecommendationSelect,JobSkillImportanceR,JobSkillImportancePython,JobSkillImportanceSQL,JobSkillImportanceBigData)] > dim(responses) ## [1] 15859 16
通过初步的列筛选,笔者保留了表7-1中列出的16个变量。
这里的清洗只是一部分,下面笔者还会展示多对数据进行清洗处理和重塑的过程。
首先查看受访者的年龄。从数据框中选取Age列,然后通过管道函数(%>%)传递给unique函数去重并检视数值情况。喜欢尝试的读者,可以尝试使用range、max或min这类简单基础的函数进行基础的数据探索,以方便确定下一步的处理方向。示例代码具体如下:
> responses$Age %>% unique() ##[1] NA 30 28 56 46 35 22 43 33 20 27 26 54 58 24 39 49 ##[18] 25 21 51 34 41 32 53 29 36 23 48 37 63 40 31 59 38 ##[35] 44 47 19 50 68 16 42 60 18 0 62 57 72 13 55 52 17 ##[52] 15 69 11 70 65 45 14 64 80 6 61 66 100 1 10 67 73 ##[69] 71 74 75 3 77 76 79 99 12 4 2 94 83 78 9 82 98
在变量Age中,读者应该不难发现有些受访者的回答是不切实际或是带着玩笑成分的。默认值NA可以理解为不想要回答或是忘记回答。但是0岁或者1岁这样的年龄似乎有些不切实际。100岁的老数据科学家并不是不可能,但读者需要小心这样的回答是否与该受访者的其他回答相符。具体来说,如果该百岁受访者的受雇情况为非退休(retired)状态,那读者就要三思了。
下面介绍几种可能性来对该情况进行清洗。读者可以使用grep函数配合正则表达式来确定具体年龄受访者的观测值位置,通过其在数据框中的具体位置来去除其所在的行。第二行代码中为data.table包方式,通过对i部分进行设置来筛选行观测值(详情请参见第6章)。笔者更青睐使用后者,不仅仅是因为其速度优势,更是因为data.table包对数据在console中展示部分的优化使得数据的检视变得更加清晰且容易。示例代码具体如下:
> responses$Age%>% grep("^1$", x = .) ## [1] 2049 4814 14125 15793 > responses[Age!= 1][,1:2] ## Age Country ## 1: 30 United States ## 2: 28 Canada ## 3: 56 United States ## 4: 46 Brazil ## 5: 35 United States ## --- ## 15533: 21 Indonesia ## 15534: 24 Other ## 15535: 25 Indonesia ## 15536: 16 Singapore ## 15537: 27 Japan
当然,读者可以选择保留全部数据,但是需要按照特定条件对其进行数值替换。这里用到了判别句式ifelse,其使用方法如下:
ifelse(cond,statement1,statement2)
该函数是判别句式if/else的向量化版本,其中,若cond(判别条件)成立(为真),则执行statement1(结果1),否则执行statement2(结果2)。下列第一行代码中的判别条件设置为0~3岁和100岁的受访者都是理论外的级别,为了不过度影响年龄分布情况,暂定为7岁。若在后续分析中发现将百岁受访者改为7岁神童与其他指标冲突,则读者重新设置这一项即可。
第二行代码用于检测除了默认值以外的观测值中,是否还存在过于离谱的年龄(Age)值。如果读者仍不满意结果,可继续进行进一步的清理,实现代码具体如下:
> responses$Age <- ifelse(responses$Age %in% c(0:3, 100), 7, responses$Age) > responses[!is.na(Age)]$Age%>% unique() ## [1] 30 28 56 46 35 22 43 33 20 27 26 54 58 24 39 49 25 21 51 34 41 32 53 ## [24] 29 36 23 48 37 63 40 31 59 38 44 47 19 50 68 16 42 60 18 7 62 57 72 ## [47] 13 55 52 17 15 69 11 70 65 45 14 64 80 6 61 66 10 67 73 71 74 75 77 ## [70] 76 79 99 12 4 94 83 78 9 82 98