#### 数据整理 科学实验原始数据格式多种多样,这给数据处理分析带来困难。如果有一个统一的数据格式,可以降低数据的复杂性,便于理解和交流,也给统计程序开发者提供方便,增加数据逻辑的使用范围。庆幸的是,科学数据都可以转化为字段和记录两向列表的形式。这个两向表遵循以下三条规则: * 列代表变量(或字段),每个变量一列 * 行代表观测(或记录),每个观测值一行 * 每个单元格代表该变量在该观测中的观测值 这是日常生活和科研记录中的常用记录数据形式,但为了节省纸张、或者为了数据紧凑直观,有时候也不这样记录,特别是对于多因素试验的情况。比如,这个表: 为了数据分析的需要,需要先将这种形式的数据转化为上述标准格式。这个过程叫做数据整理(tidy),整理好的标准数据也叫做tidy数据。 ##### tidyverse、tidyr tidyverse是用于数据整理的R包。 安装:install.packages('tidyverse') 或者安装其轻量版本 install.packages("tidyr") 如想使用最新版本,可以从源码安装: install.packages("devtools") devtools::install_github("tidyverse/tidyr") 使用: library('tidyr') #### 筛选记录(filter) filter(flights, month == 1, day == 1) 比较运算符:>, >=, <, <=, != (不等于), and == (等于). 注意,等于是==而不是=,前者是比较运算符,后者是赋值运算符,这一点容易出错。 另外需要注意的是在使用==比较浮点数时,计算机提供的有限精度的近似而不是绝对精确的数值(物质的有限可分性原理) sqrt(2) ^ 2 其实并不等于2,测试一下: ```{r} sqrt(2) ^ 2 #> [1] FALSE 1/49 * 49 == 1 #> [1] FALSE ``` 这时不要使用==,代之以near()函数: ```{r} near(sqrt(2) ^ 2, 2) #> [1] TRUE near(1 / 49 * 49, 1) #> [1] TRUE ``` 逻辑运算符:|、& 、!、xor filter(flights, month == 11 | month == 12) #### 排序(arrange) arrange(flights, year, month, desc(day)) #### 选择列(select) * 按列名选择: select(flights, year, month, day) * 选择两个列之间的所有列,包括自身,[year:day] select(flights, year:day) * 排除选择: select(flights, -(year:day)) * 选择开头 starts_with("abc")//匹配列名以“abc”开头的列。 * 选择结尾: ends_with("xyz"): //匹配列名以“xyz”结尾的列. * 包含: contains("ijk") //匹配列名包含"ijk"的列 * 匹配正则表达式 matches("(.)\\1"): 匹配列名有重复字符的列。 * 匹配数字范围 num_range("x", 1:3) //匹配列名为x1,x2,x3 #### 重命名列(rename) rename(flights, tail_num = tailnum) #### 变异(mutate) mutate(突变,变异),如病毒变异、DNA突变。 mutate从现有变量产生新的变量,并加到现有变量的后面。 ```{r} flights_sml <- select(flights, year:day, ends_with("delay"), distance, air_time ) mutate(flights_sml, gain = arr_delay - dep_delay, speed = distance / air_time * 60 ) ``` 如果只需要新的变量,而不包括原有变量,使用transmute ```{r} transmute(flights, gain = arr_delay - dep_delay, hours = air_time / 60, gain_per_hour = gain / hours ) ``` 运算符:%/% 整除, %% 求余, +, -, *, /, sum(), log(), log2(), log10(() , lead(), tag() #### 分组汇总(summarize) summarise(flights, delay = mean(dep_delay, na.rm = TRUE)) summarize()与group_by()配合使用。 ```{r} by_day <- group_by(flights, year, month, day) summarise(by_day, delay = mean(dep_delay, na.rm = TRUE)) ``` #### 使用管道(%>%) 对于一系列的操作,组成一个操作序列的情况,前一个操作的结果作为后一个操作的参数。这时可以通过管道来组织代码,使得整个流程更加清晰,代码的可读性也会提高。数据作为参数在函数中流动,与物体在管道中的流动模型十分相似,因此这种组合的处理方式叫做管道,管道符号为%>%,前一个函数的输出结果,作为后一个函数的第一个参数输入并且书写是省略参数名,而默认为第一个参数。如,x %>% f(y) 变成 f(x, y), 而x %>% f(y) %>% g(z) 变成 g(f(x, y), z)。 ```{r} delays <- flights %>% group_by(dest) %>% summarise( count = n(), dist = mean(distance, na.rm = TRUE), delay = mean(arr_delay, na.rm = TRUE) ) %>% filter(count > 20, dest != "HNL") ``` 这样处理流程更清晰,代码更整洁了。 #### 有用的汇总函数 ##### 位置量度 mean()、median() 平均值和中位数 ```{r} not_cancelled %>% group_by(year, month, day) %>% summarise( avg_delay1 = mean(arr_delay), avg_delay2 = mean(arr_delay[arr_delay > 0]) # the average positive delay ) ``` ##### 分散量度 sd()、IQR()、mad() ```{r} not_cancelled %>% group_by(dest) %>% summarise(distance_sd = sd(distance)) %>% arrange(desc(distance_sd)) ``` ##### Measures of rank: min(x), quantile(x, 0.25), max() ```{r} not_cancelled %>% group_by(year, month, day) %>% summarise( first = min(dep_time), last = max(dep_time) ) ``` ##### Measures of position: first(x), nth(x, 2), last(x) ```{r} not_cancelled %>% group_by(year, month, day) %>% summarise( first_dep = first(dep_time), last_dep = last(dep_time) ) ``` ##### 计数 n() n()函数返回当前组的大小,即当前组包含的记录数。 sum(!is.na(x))返回非空记录数,n_distinct(x)返回非重复记录数。 ```{r} not_cancelled %>% group_by(dest) %>% summarise(carriers = n_distinct(carrier)) %>% arrange(desc(carriers)) ``` 计数 ```{r} not_cancelled %>% count(dest) ``` 加权计数: ```{r} not_cancelled %>% count(tailnum, wt = distance) ``` ##### 计数和比例 sum(x > 10), 当x为数值型,TRUE转化为1,FALSE转化为0,然后计算总和,这实际上是对满足该条件的记录数。mean(y == 0)则返回满足该条件的记录占总记录数的比例。 #### 多变量分组 daily <- group_by(flights, year, month, day)