Tidyverse ------Tidyr

趁着今天有时间,想着是不是该记录点东西了,没错是该记录一下了。今天的重头戏是tidyr package。
Tidy datasets are all alike, but every messy dataset is messy in its own way 。这是 Hadley Wickham(牛人)的总结。
数据预处理对于后续的分析很关键,处理过后的Tidy data 只要有三类特征:

  1. 每一列代表一个变量
  2. 每一行代表一个观测值
  3. 每一单元格代表一个value
    在Tidyverse(它是由RStudio选出多个资料科学应用套件的集合)中其他一些如dplyr、ggplot2等都是基于Tidy tada,下面这张图片很好的说明了tidy data的数据结构。这个内容也是我最近在学习的内容。


    2019-05-02 20-20-20 的屏幕截图.png

1. spreading and gathering

拿到一个数据首先要分辨出观测值和变量,然后就是解决两个很常见的问题:

  1. 一个变量分散在多列
  2. 一个观测分散在多行
    因此,就要进行长宽数据结构的转换,因此你需要用到tidyr package 中两个重要的函数: spread 和 gather

1.1 gather

让数据变成长窄型


2019-05-02 21-31-21 的屏幕截图.png
> table4a
# A tibble: 3 x 3
  country             `1999`  `2000`
* <chr>                   <int>      <int>
1 Afghanistan      745         2666
2 Brazil                37737       80488
3 China                212258    213766
对于上面的数据,可以看出1999和2000两列可以合并成一个新变量year,要完成这个转换:
        Usage :    gather(key= , value=  , ...)
          1. 为需要合并的多列定义新的变量名,key = "year"
          2. 为分布在单元格变量定义一个变量名,value = "cases"
          3. 设置需要合并成一个变量的列名,`1999`,`2000`,若需要合并成多列可直接指定列的索引值

tidy4a <- table4a  %>%  gahter (key = "year", value = "cases", `1999`,`2000`)
> tidy4a
# A tibble: 6 x 3
  country                    year   cases
  <chr>                        <chr>  <int>
1 Afghanistan         1999     745
2 Brazil                      1999   37737
3 China                     1999  212258
4 Afghanistan         2000    2666
5 Brazil                      2000   80488
6 China                      2000  213766

1.2 spread

让数据变成宽短型


2019-05-02 21-33-25 的屏幕截图.png
> table2
# A tibble: 12 x 4
   country                   year              type            count
   <chr>                      <int>             <chr>           <int>
 1 Afghanistan       1999              cases             745
 2 Afghanistan       1999         population   19987071
 3 Afghanistan       2000              cases            2666
 4 Afghanistan       2000         population   20595360
 5 Brazil                    1999             cases           37737
 6 Brazil                    1999         population  172006362
 7 Brazil                    2000            cases           80488
 8 Brazil                    2000        population   174504898
 9 China                   1999            cases            212258
10 China                  1999       population    1272915272
11 China                  2000            cases           213766
12 China                  2000       population    1280428583
对于上面的数据可以看出一个观测值是每个国家每一年的数据,然而每一个观测值确被分成两行排列,要完成这个转换:
      Usage: spread(key=  ,value = )
      1.  包含变量名的列,即key列,key = "type"
      2.  包含value的列,即value列,value = "count"
      对于这个函数的理解,将type列和count列每一行数据看成key-value pair ,从而利用spread对每一个key-value进行列的转换

table2 %>% spread(key = "type",value = "count")
# A tibble: 6 x 4
  country                   year         cases      population
  <chr>                       <int>         <int>          <int>
1 Afghanistan         1999          745         19987071
2 Afghanistan         2000         2666        20595360
3 Brazil                      1999        37737      172006362
4 Brazil                      2000        80488      174504898
5 China                     1999        212258    1272915272
6 China                     2000        213766    1280428583

2. Separating and uniting

对于一些数据,如果每一列的每一个单元格是由多个变量组成,那么我们需要将这一列分割成两列,这时候就要用到separate ; 又或者将多列合并成一列,就要用到unite

2.1 separate

> table3
# A tibble: 6 x 3
  country                    year             rate             
* <chr>                      <int>           <chr>            
1 Afghanistan          1999           745/19987071     
2 Afghanistan          2000           2666/20595360    
3 Brazil                       1999           37737/172006362  
4 Brazil                       2000           80488/174504898  
5 China                      1999            212258/1272915272
6 China                      2000            213766/1280428583
    Usage: separate (col = , into =  , sep =  )
    1. 定义需要分割的列名 col = "rate"
    2. 定义分割后的多个列名 into = c("cases", "population")
    3. 指定分隔符,默认以非字母、数字为分割符,也可用数字指定从字符串的那个字符分割

table3 %>% separate(col = rate,into = c("cases","population"))
# A tibble: 6 x 4
  country                             year    cases       population
  <chr>                                <int>    <chr>         <chr>     
1 Afghanistan                 1999      745          19987071  
2 Afghanistan                 2000     2666        20595360  
3 Brazil                             1999      37737     172006362 
4 Brazil                             2000      80488     174504898 
5 China                            1999      212258   1272915272
6 China                            2000      213766   1280428583
从返回的结果可以看出新生成的cases 和population两列数据类型为数值型,而结果是字符型,因此需要指定参数convert = TRUE
table3 %>% separate(col = rate,into = c("cases","population"),convert = TRUE)

table3 %>%  separate(year, into = c("century", "year"), sep = 2) # 表示从year列中第二个字符后进行分割
# A tibble: 6 x 4
  country                 century              year           rate             
  <chr>                      <chr>                 <chr>       <chr>            
1 Afghanistan          19                       99             745/19987071     
2 Afghanistan          20                       00             2666/20595360    
3 Brazil                       19                       99             37737/172006362  
4 Brazil                       20                       00             80488/174504898  
5 China                      19                       99              212258/1272915272
6 China                      20                       00              213766/1280428583

2.2 unite

对上面的数据century和year 两列进行合并
    Usage : unite(col = , ... , sep = ,)
    1. 定义合并后的列名
    2. 指定需要合并的多列(列名或索引)
    3. 指定合并后来自不同列数据的连接符,默认是"_" 

unite (col = "new" , "century", "year", sep = "")
# A tibble: 6 x 3
  country                    year             rate             
* <chr>                      <int>           <chr>            
1 Afghanistan          1999           745/19987071     
2 Afghanistan          2000           2666/20595360    
3 Brazil                       1999           37737/172006362  
4 Brazil                       2000           80488/174504898  
5 China                      1999            212258/1272915272
6 China                      2000            213766/1280428583

3. missing value

改变数据结构的同时,会出现一些缺失值,缺失值主要有以下两种方式: 1、原数据集中有NA 标记 ; 2、 有些观测值不存在数据集中

> stocks
# A tibble: 7 x 3
   year      qtr     return
  <dbl>  <dbl>  <dbl>
1  2015     1       1.88
2  2015     2       0.59
3  2015     3       0.35
4  2015     4       NA   
5  2016     2      0.92
6  2016     3      0.17
7  2016     4      2.66
观测数据可以看出: 有一个明确的缺失值NA, 还有一个隐藏的观测值缺失
为了让隐藏的缺失值变成NA,可以spread 将year列展开

stocks %>% spread(key = year,value = return)
>stocks
# A tibble: 4 x 3
    qtr     `2015`  `2016`
  <dbl>   <dbl>     <dbl>
1     1        1.88         NA   
2     2        0.59        0.92
3     3        0.35        0.17
4     4         NA          2.66
一般原本存在的NA可能不是很重要,因此你可以利用gather将NA变成隐藏的缺失。

stocks %>% spread(key = year,value = return)  %>% gather (key = "year" , value = "return" ,`2015`,`2016`, na.rm = TRUE)
# A tibble: 6 x 3
    qtr        year        count
  <dbl>   <chr>      <dbl>
1     1       2015        1.88
2     2       2015        0.59
3     3       2015        0.35
4     2       2016        0.92
5     3       2016        0.17
6     4       2016        2.66

另一个让隐藏的缺失值变成NA的函数: complete()
stocks %>%  complete(year, qtr) #列出year和qtr所有的观测组合
# A tibble: 8 x 3
   year          qtr   return
  <dbl>     <dbl>  <dbl>
1  2015         1       1.88
2  2015         2       0.59
3  2015         3       0.35
4  2015         4        NA   
5  2016         1        NA   
6  2016         2       0.92
7  2016         3       0.17
8  2016         4       2.66

还有一种情况就是对于数据录入员来说,有时候缺失值表示与之前值相同故而省略
> treament
# A tibble: 4 x 3
  person                     treament     response
  <chr>                           <dbl>          <dbl>
1 Derrick Whitmore        1                  7
2 NA                                       2                10
3 NA                                       3                  7
4 Katherine Burke           1                  4

treatment %>% fill(person)

# A tibble: 4 x 3
  person                              treament response
  <chr>                                    <dbl>    <dbl>
1 Derrick Whitmore              1             7
2 Derrick Whitmore              2            10
3 Derrick Whitmore              3             7
4 Katherine Burke                 1             4

有了Tidy data,我们就可以开展后续数据整理和分析,这就要介绍到Tidyverse家族另一个重要的dplyr package,可以实现类似SQL的功能,虽然一些R基础包中函数也可以完成目标,但是当你熟悉了dplyr的操作,你会感到很High!!!

附上原文链接: https://r4ds.had.co.nz/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容