R语言数据分析(五)



前言

我们学习了数据导入、可视化以及数据转换的相关知识,那么在数据导入后要进行的就是数据的整理,这是一个将凌乱的数据整理成为整洁数据的过程。只有整洁的数据才能很好的进行数据转换分析以及可视化。在这一节的学习中我们将会使用一种称为tidy data的系统在R中组织数据。(注意加载tidyverse包)

一、什么是整洁的数据

数据的呈现方式多种多样,下面的示例展示了三种不同的方式整理的相同的数据。每个数据都用于显示一组数据,包括:英雄名称、版本、攻击力和防御力数值,但每个数据集组织这些值的方式不同:

# 这里是我自定义的table1、2、3,可以自己去自定义一些tibble顺便复习前面的知识了,其实在tidyverse中也有自己的table1、2、3存在,可以自行查看。
table1
#> # A tibble: 6 × 4
#>   Hero  Version   ATK   DEF
#>   <chr>   <dbl> <dbl> <dbl>
#> 1 LMY         1   999 666  
#> 2 LMY         2  1000 999  
#> 3 NEW         1    99  66  
#> 4 NEW         2   100  99  
#> 5 Z           1     5   1  
#> 6 Z           2     5   0.5

table2
#> # A tibble: 12 × 4
#>    Hero  Version type   value
#>    <chr>   <dbl> <chr>  <dbl>
#>  1 LMY         1 ATK    999  
#>  2 LMY         1 DEF    666  
#>  3 LMY         2 ATK   1000  
#>  4 LMY         2 DEF    999  
#>  5 NEW         1 ATK     99  
#>  6 NEW         1 DEF    100  
#>  7 NEW         2 ATK     66  
#>  8 NEW         2 DEF     99  
#>  9 Z           1 ATK      5  
#> 10 Z           1 DEF      5  
#> 11 Z           2 ATK      1  
#> 12 Z           2 DEF      0.5

table3
#> # A tibble: 6 × 3
#>   Hero  Version  rate
#>   <chr>   <dbl> <dbl>
#> 1 LMY         1 1.5  
#> 2 LMY         2 1.00 
#> 3 NEW         1 0.99 
#> 4 NEW         2 0.667
#> 5 Z           1 1    
#> 6 Z           2 2

其中table1是在tidyverse中容易使用的形式,以为它是tidy的。

整洁的数据集需要遵循三个相互关联的规则:

  1. 每个变量都是一列,每一列都是一个变量。

  2. 每个观测值都是一行,每一行都是一个观测值。

  3. 每个值都是一个单元格,每个单元格都是一个值。

保持数据的整洁主要有两个优点:

  1. 一致的数据存储方式有一个普遍的优势。更易于学习工具,具有底层的一致性

  2. 变量放在列中有一个特定的优势,以为它很贴合R的矢量化性质。

tidyverse中所有软件包都旨在处理整洁的数据,下面是一些小示例:

table1 |> 
  mutate(rate = ATK / DEF)
#> # A tibble: 6 × 5
#>   Hero  Version   ATK   DEF  rate
#>   <chr>   <dbl> <dbl> <dbl> <dbl>
#> 1 LMY         1   999 666    1.5 
#> 2 LMY         2  1000 999    1.00
#> 3 NEW         1    99  66    1.5 
#> 4 NEW         2   100  99    1.01
#> 5 Z           1     5   1    5   
#> 6 Z           2     5   0.5 10

table1 |> 
  group_by(Version) |> 
  summarize(total_version = sum(ATK))
#> # A tibble: 2 × 2
#>   Version total_version
#>     <dbl>         <dbl>
#> 1       1          1103
#> 2       2          1105

ggplot(table1, aes(x = Version, y = ATK)) +
  geom_line(aes(group = Hero), color = "Blue") + 
  geom_point(aes(color = Hero, shape = Hero)) +
  scale_x_continuous(breaks = c(1.0, 2.0))

R语言数据分析(五)-LMLPHP

二、延长数据

整洁数据的原则看起来十分简单,但是在大多数情况下,遇到的数据都是不整洁的。这就意味着大多数实际分析至少需要一点整理。

首先要弄清楚基础变量和观察值是什么。接下来,要将数据转化为整洁的形式,列包含变量,行包含观测值。

2.1 列名中的数据值

tidyverse中的billboard数据集记录了2000年歌曲广告排名:

billboard
#> # A tibble: 317 × 79
#>    artist     track date.entered   wk1   wk2   wk3   wk4   wk5   wk6   wk7   wk8
#>    <chr>      <chr> <date>       <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#>  1 2 Pac      Baby… 2000-02-26      87    82    72    77    87    94    99    NA
#>  2 2Ge+her    The … 2000-09-02      91    87    92    NA    NA    NA    NA    NA
#>  3 3 Doors D… Kryp… 2000-04-08      81    70    68    67    66    57    54    53
#>  4 3 Doors D… Loser 2000-10-21      76    76    72    69    67    65    55    59
#>  5 504 Boyz   Wobb… 2000-04-15      57    34    25    17    17    31    36    49
#>  6 98^0       Give… 2000-08-19      51    39    34    26    26    19     2     2
#>  7 A*Teens    Danc… 2000-07-08      97    97    96    95   100    NA    NA    NA
#>  8 Aaliyah    I Do… 2000-01-29      84    62    51    41    38    35    35    38
#>  9 Aaliyah    Try … 2000-03-18      59    53    38    28    21    18    16    14
#> 10 Adams, Yo… Open… 2000-08-26      76    76    74    69    68    67    61    58
#> # ℹ 307 more rows
#> # ℹ 68 more variables: wk9 <dbl>, wk10 <dbl>, wk11 <dbl>, wk12 <dbl>,
#> #   wk13 <dbl>, wk14 <dbl>, wk15 <dbl>, wk16 <dbl>, wk17 <dbl>, wk18 <dbl>,
#> #   wk19 <dbl>, wk20 <dbl>, wk21 <dbl>, wk22 <dbl>, wk23 <dbl>, wk24 <dbl>,
#> #   wk25 <dbl>, wk26 <dbl>, wk27 <dbl>, wk28 <dbl>, wk29 <dbl>, wk30 <dbl>,
#> #   wk31 <dbl>, wk32 <dbl>, wk33 <dbl>, wk34 <dbl>, wk35 <dbl>, wk36 <dbl>,
#> #   wk37 <dbl>, wk38 <dbl>, wk39 <dbl>, wk40 <dbl>, wk41 <dbl>, wk42 <dbl>, …

其中,每个观测值是一首歌,前三列是歌曲信息,之后有76列来描述歌曲每周的排名。这76列中,列名是一个变量(week),单元格值是另一个变量(week rank)。

为了整理这些数据,我们使用pivot_longer()函数:

billboard |> 
  pivot_longer(
    cols = starts_with("wk"),
    names_to = "week",
    values_to = "rank"
  )
#> # A tibble: 24,092 × 5
#>    artist track                   date.entered week   rank
#>    <chr>  <chr>                   <date>       <chr> <dbl>
#>  1 2 Pac  Baby Don't Cry (Keep... 2000-02-26   wk1      87
#>  2 2 Pac  Baby Don't Cry (Keep... 2000-02-26   wk2      82
#>  3 2 Pac  Baby Don't Cry (Keep... 2000-02-26   wk3      72
#>  4 2 Pac  Baby Don't Cry (Keep... 2000-02-26   wk4      77
#>  5 2 Pac  Baby Don't Cry (Keep... 2000-02-26   wk5      87
#>  6 2 Pac  Baby Don't Cry (Keep... 2000-02-26   wk6      94
#>  7 2 Pac  Baby Don't Cry (Keep... 2000-02-26   wk7      99
#>  8 2 Pac  Baby Don't Cry (Keep... 2000-02-26   wk8      NA
#>  9 2 Pac  Baby Don't Cry (Keep... 2000-02-26   wk9      NA
#> 10 2 Pac  Baby Don't Cry (Keep... 2000-02-26   wk10     NA
#> # ℹ 24,082 more rows

使用此函数需要注意:

  • cols参数用于指定哪些列需要进行整合,这个参数使用的语法与select()相同,因此可以使用!c(artist, track, data.entered)或者starts_with("wk")

  • names_to参数对存储在列名中的变量进行命名。

  • values_to参数将存储在单元格中的变量进行命名。

我们注意到转化后的数据中有NA值。比如数据的第8行就存在。这是因为这首歌在第8周并未进入前100名所导致的。那么这些NA并不是真正的观察结果。因此可以使用参数values_drop_na = TRUE来使得pivot_longer()删除NA

现在数据就是整洁的了,不过我们可以通过使用mutate()readr::parse_number()来将字符串变为数字,parse_number()函数将从字符串提取第一个数字,忽略所有其他文本:

billboard_longer <- billboard |> 
  pivot_longer(
    cols = starts_with("wk"),
    names_to = "week",
    values_to = "rank",
    values_drop_na = TRUE
  ) |> 
  mutate(
    week = parse_number(week)
  )
billboard_longer
#> # A tibble: 5,307 × 5
#>    artist  track                   date.entered  week  rank
#>    <chr>   <chr>                   <date>       <dbl> <dbl>
#>  1 2 Pac   Baby Don't Cry (Keep... 2000-02-26       1    87
#>  2 2 Pac   Baby Don't Cry (Keep... 2000-02-26       2    82
#>  3 2 Pac   Baby Don't Cry (Keep... 2000-02-26       3    72
#>  4 2 Pac   Baby Don't Cry (Keep... 2000-02-26       4    77
#>  5 2 Pac   Baby Don't Cry (Keep... 2000-02-26       5    87
#>  6 2 Pac   Baby Don't Cry (Keep... 2000-02-26       6    94
#>  7 2 Pac   Baby Don't Cry (Keep... 2000-02-26       7    99
#>  8 2Ge+her The Hardest Part Of ... 2000-09-02       1    91
#>  9 2Ge+her The Hardest Part Of ... 2000-09-02       2    87
#> 10 2Ge+her The Hardest Part Of ... 2000-09-02       3    92
#> # ℹ 5,297 more rows

现在我们就可以对这样的结果进行很好的可视化了

billboard_longer |> 
  ggplot(aes(x = week, y = rank, group = track)) + 
  geom_line(alpha = 0.1) +
  scale_y_reverse()

R语言数据分析(五)-LMLPHP

2.2 pivot_longer()的处理原理

明白使用函数pivot_longer()处理的原理很重要,这样我们就能够在需要使用这些功能的时候能更快的想到该函数。

假设我们有三个小朋友,记为A、B、C。两年分别测量了两次身高。我们建立一个tibble表格来记录数据:

df <- tribble(
  ~id, ~h1, ~h2,
  "A", 110, 130,
  "B", 100, 110,
  "C", 80, 135
)

我们经过处理后得到以下数据集:

df |> 
  pivot_longer(
    cols = h1:h2,
    names_to = "year_h",
    values_to = "value"
  )
#> # A tibble: 6 × 3
#>   id    year_h value
#>   <chr> <chr>  <dbl>
#> 1 A     h1       110
#> 2 A     h2       130
#> 3 B     h1       100
#> 4 B     h2       110
#> 5 C     h1        80
#> 6 C     h2       135

函数如何工作的呢?逐列来看,我们发现了其工作模式。如下图所示:

R语言数据分析(五)-LMLPHP

  1. 已有的列重复了cols参数中列数的次数

  2. cols参数中的列名重复了行数的次数

  3. cols参数中列的值从上到下从左到右依次进行排列

2.3 列名中包含许多变量的情况

有时列名可能包含许多信息。比如,在who2上可以看到WHO发布的关于结核病诊断的信息:

who2
#> # A tibble: 7,240 × 58
#>    country      year sp_m_014 sp_m_1524 sp_m_2534 sp_m_3544 sp_m_4554 sp_m_5564
#>    <chr>       <dbl>    <dbl>     <dbl>     <dbl>     <dbl>     <dbl>     <dbl>
#>  1 Afghanistan  1980       NA        NA        NA        NA        NA        NA
#>  2 Afghanistan  1981       NA        NA        NA        NA        NA        NA
#>  3 Afghanistan  1982       NA        NA        NA        NA        NA        NA
#>  4 Afghanistan  1983       NA        NA        NA        NA        NA        NA
#>  5 Afghanistan  1984       NA        NA        NA        NA        NA        NA
#>  6 Afghanistan  1985       NA        NA        NA        NA        NA        NA
#>  7 Afghanistan  1986       NA        NA        NA        NA        NA        NA
#>  8 Afghanistan  1987       NA        NA        NA        NA        NA        NA
#>  9 Afghanistan  1988       NA        NA        NA        NA        NA        NA
#> 10 Afghanistan  1989       NA        NA        NA        NA        NA        NA
#> # ℹ 7,230 more rows
#> # ℹ 50 more variables: sp_m_65 <dbl>, sp_f_014 <dbl>, sp_f_1524 <dbl>,
#> #   sp_f_2534 <dbl>, sp_f_3544 <dbl>, sp_f_4554 <dbl>, sp_f_5564 <dbl>,
#> #   sp_f_65 <dbl>, sn_m_014 <dbl>, sn_m_1524 <dbl>, sn_m_2534 <dbl>,
#> #   sn_m_3544 <dbl>, sn_m_4554 <dbl>, sn_m_5564 <dbl>, sn_m_65 <dbl>,
#> #   sn_f_014 <dbl>, sn_f_1524 <dbl>, sn_f_2534 <dbl>, sn_f_3544 <dbl>,
#> #   sn_f_4554 <dbl>, sn_f_5564 <dbl>, sn_f_65 <dbl>, ep_m_014 <dbl>, …

除了country和year列外,剩下56列命名格式统一,由三部分组成分别是诊断方法、性别和年龄范围,用_分隔。这种情况下记录了6条消息。我们可以使用pivot_longer将其分开:

who2 |> 
  pivot_longer(
    cols = !(country:year),
    names_to = c("diagnosis","gender", "age"),
    names_sep = "_",
    values_to = "count"
  )
#> # A tibble: 405,440 × 6
#>    country      year diagnosis gender age   count
#>    <chr>       <dbl> <chr>     <chr>  <chr> <dbl>
#>  1 Afghanistan  1980 sp        m      014      NA
#>  2 Afghanistan  1980 sp        m      1524     NA
#>  3 Afghanistan  1980 sp        m      2534     NA
#>  4 Afghanistan  1980 sp        m      3544     NA
#>  5 Afghanistan  1980 sp        m      4554     NA
#>  6 Afghanistan  1980 sp        m      5564     NA
#>  7 Afghanistan  1980 sp        m      65       NA
#>  8 Afghanistan  1980 sp        f      014      NA
#>  9 Afghanistan  1980 sp        f      1524     NA
#> 10 Afghanistan  1980 sp        f      2534     NA
#> # ℹ 405,430 more rows

另外还有一种方法可以替代names_sep就是names_pattern,这需要用到正则表达式来提取变量,我们后续在逐步介绍。

从原理上来看,他是将原来names_to参数使用的列排列完之后,又按照names_sep的规则进行了分列。

2.4 列名同时包含数据和变量

有些更复杂的数据集,其列名同时包含了数据和变量。比如:

household
#> # A tibble: 5 × 5
#>   family dob_child1 dob_child2 name_child1 name_child2
#>    <int> <date>     <date>     <chr>       <chr>      
#> 1      1 1998-11-26 2000-01-29 Susan       Jose       
#> 2      2 1996-06-22 NA         Mark        <NA>       
#> 3      3 2002-07-11 2004-04-05 Sam         Seth       
#> 4      4 2004-10-10 2009-08-27 Craig       Khai       
#> 5      5 2000-12-05 2005-02-28 Parker      Gracie

这里记录了5个家庭数据,其中最多包含两个孩子的姓名及出生日期。这个数据集的列名中包含了两个变量的名称(namedob),以及另一个变量的值(child的值12)。此时想要解决这个问题,names_to会使用特殊的".value"作为值的指示,而不是新列名,这样会覆盖掉values_to的参数:

household |> 
  pivot_longer(
    cols = !family,
    names_to = c(".value", "child"),
    names_sep = "_",
    values_drop_na = TRUE
  )
#> # A tibble: 9 × 4
#>   family child  dob        name  
#>    <int> <chr>  <date>     <chr> 
#> 1      1 child1 1998-11-26 Susan 
#> 2      1 child2 2000-01-29 Jose  
#> 3      2 child1 1996-06-22 Mark  
#> 4      3 child1 2002-07-11 Sam   
#> 5      3 child2 2004-04-05 Seth  
#> 6      4 child1 2004-10-10 Craig 
#> 7      4 child2 2009-08-27 Khai  
#> 8      5 child1 2000-12-05 Parker
#> 9      5 child2 2005-02-28 Gracie

具体情况就像上面这样,一目了然。

三、扩宽数据

有时一个观测值的指标可能分布在多行中,这时我们就可以通过增加列和减少行的方法来扩宽数据集。使用到的函数是pivot_wider。比如下面的数据集:

cms_patient_experience
#> # A tibble: 500 × 5
#>    org_pac_id org_nm                           measure_cd measure_title prf_rate
#>    <chr>      <chr>                            <chr>      <chr>            <dbl>
#>  1 0446157747 USC CARE MEDICAL GROUP INC       CAHPS_GRP… CAHPS for MI…       63
#>  2 0446157747 USC CARE MEDICAL GROUP INC       CAHPS_GRP… CAHPS for MI…       87
#>  3 0446157747 USC CARE MEDICAL GROUP INC       CAHPS_GRP… CAHPS for MI…       86
#>  4 0446157747 USC CARE MEDICAL GROUP INC       CAHPS_GRP… CAHPS for MI…       57
#>  5 0446157747 USC CARE MEDICAL GROUP INC       CAHPS_GRP… CAHPS for MI…       85
#>  6 0446157747 USC CARE MEDICAL GROUP INC       CAHPS_GRP… CAHPS for MI…       24
#>  7 0446162697 ASSOCIATION OF UNIVERSITY PHYSI… CAHPS_GRP… CAHPS for MI…       59
#>  8 0446162697 ASSOCIATION OF UNIVERSITY PHYSI… CAHPS_GRP… CAHPS for MI…       85
#>  9 0446162697 ASSOCIATION OF UNIVERSITY PHYSI… CAHPS_GRP… CAHPS for MI…       83
#> 10 0446162697 ASSOCIATION OF UNIVERSITY PHYSI… CAHPS_GRP… CAHPS for MI…       63
#> # ℹ 490 more rows

该数据集研究的目标是一个组织,但是每个组织的数据被分布在了6行中,调查组织中的每个测量值各占一行。我们可以看到:

cms_patient_experience |> 
  distinct(measure_cd, measure_title)
#> # A tibble: 6 × 2
#>   measure_cd   measure_title                                                    
#>   <chr>        <chr>                                                            
#> 1 CAHPS_GRP_1  CAHPS for MIPS SSM: Getting Timely Care, Appointments, and Infor…
#> 2 CAHPS_GRP_2  CAHPS for MIPS SSM: How Well Providers Communicate               
#> 3 CAHPS_GRP_3  CAHPS for MIPS SSM: Patient's Rating of Provider                 
#> 4 CAHPS_GRP_5  CAHPS for MIPS SSM: Health Promotion and Education               
#> 5 CAHPS_GRP_8  CAHPS for MIPS SSM: Courteous and Helpful Office Staff           
#> 6 CAHPS_GRP_12 CAHPS for MIPS SSM: Stewardship of Patient Resources

这两列都不是很好的变量名,其中measure_cd并没有按时变量的含义,measure_tittle也只是包含一个长句子。现在,让我们使用measure_cd列作为我们新列名的源。创建一个新的数据集:

cms_patient_experience |> 
  pivot_wider(
    names_from = measure_cd,
    values_from = prf_rate
  )
#> # A tibble: 500 × 9
#>    org_pac_id org_nm           measure_title CAHPS_GRP_1 CAHPS_GRP_2 CAHPS_GRP_3
#>    <chr>      <chr>            <chr>               <dbl>       <dbl>       <dbl>
#>  1 0446157747 USC CARE MEDICA… CAHPS for MI…          63          NA          NA
#>  2 0446157747 USC CARE MEDICA… CAHPS for MI…          NA          87          NA
#>  3 0446157747 USC CARE MEDICA… CAHPS for MI…          NA          NA          86
#>  4 0446157747 USC CARE MEDICA… CAHPS for MI…          NA          NA          NA
#>  5 0446157747 USC CARE MEDICA… CAHPS for MI…          NA          NA          NA
#>  6 0446157747 USC CARE MEDICA… CAHPS for MI…          NA          NA          NA
#>  7 0446162697 ASSOCIATION OF … CAHPS for MI…          59          NA          NA
#>  8 0446162697 ASSOCIATION OF … CAHPS for MI…          NA          85          NA
#>  9 0446162697 ASSOCIATION OF … CAHPS for MI…          NA          NA          83
#> 10 0446162697 ASSOCIATION OF … CAHPS for MI…          NA          NA          NA
#> # ℹ 490 more rows
#> # ℹ 3 more variables: CAHPS_GRP_5 <dbl>, CAHPS_GRP_8 <dbl>, CAHPS_GRP_12 <dbl>

不过现在看来,我们依然为每个组织设置了多行,这是因为我们并未给出哪一列具有唯一标识,可以这样给出:

cms_patient_experience |> 
  pivot_wider(
    id_cols = starts_with("org"),
    names_from = measure_cd,
    values_from = prf_rate
  )
#> # A tibble: 95 × 8
#>    org_pac_id org_nm CAHPS_GRP_1 CAHPS_GRP_2 CAHPS_GRP_3 CAHPS_GRP_5 CAHPS_GRP_8
#>    <chr>      <chr>        <dbl>       <dbl>       <dbl>       <dbl>       <dbl>
#>  1 0446157747 USC C…          63          87          86          57          85
#>  2 0446162697 ASSOC…          59          85          83          63          88
#>  3 0547164295 BEAVE…          49          NA          75          44          73
#>  4 0749333730 CAPE …          67          84          85          65          82
#>  5 0840104360 ALLIA…          66          87          87          64          87
#>  6 0840109864 REX H…          73          87          84          67          91
#>  7 0840513552 SCL H…          58          83          76          58          78
#>  8 0941545784 GRITM…          46          86          81          54          NA
#>  9 1052612785 COMMU…          65          84          80          58          87
#> 10 1254237779 OUR L…          61          NA          NA          65          NA
#> # ℹ 85 more rows
#> # ℹ 1 more variable: CAHPS_GRP_12 <dbl>

3.1 pivot_wider的处理原理

我们还是举个前面类似的简单例子来探究处理原理:

df <- tribble(
  ~id, ~year_h, ~value,
  "A", "h1", 100,
  "B", "h1", 90,
  "A", "h2", 130,
  "B", "h2", 110,
  "A", "h3", 132
)

使用pivot_wider时将会从value列中获取值,从year_h列中获取新列名:

df |> 
pivot_wider(
  names_from = year_h,
  values_from = value
)
#> # A tibble: 2 × 4
#>   id       h1    h2    h3
#>   <chr> <dbl> <dbl> <dbl>
#> 1 A       100   130   132
#> 2 B        90   110    NA

这个过程是怎么样的呢?首先pivot_wider()会弄清楚行和列中的内容,新列名就是year_h列中的唯一值:

df |> 
  distinct(year_h) |> 
  pull()
#> [1] "h1" "h2" "h3"

默认情况下,输出的行由所有不进入新名称或者值得变量确定,它们会被认作是id.cols,这个数据集只有一列,但通常可以有多列,也可以自行指定。

df |> 
  select(-year_h, -value) |> 
  distinct()
#> # A tibble: 2 × 1
#>   id   
#>   <chr>
#> 1 A    
#> 2 B

然后pivot_wider会将这些结果组合起来生成一个用NA填充的空数据:

df |> 
  select(-year_h, -value) |> 
  distinct() |> 
  mutate(h1 = NA, h2 = NA, h3 = NA)
#> # A tibble: 2 × 4
#>   id    h1    h2    h3   
#>   <chr> <lgl> <lgl> <lgl>
#> 1 A     NA    NA    NA   
#> 2 B     NA    NA    NA

最后,pivot_wider会使用输入的数据来填充相应的位置。

如果存在多行对应一个输出的单元格会发生什么情况呢?此时在输出的数据中将会存在列内列表的结构:

df <- tribble(
  ~id, ~year_h, ~value,
  "A", "h1", 100,
  "A", "h1", 90,
  "A", "h2", 130,
  "B", "h1", 110,
  "B", "h2", 132
)

df |> 
  pivot_wider(
    names_from = year_h,
    values_from = value
  )
#> Warning: Values from `value` are not uniquely identified; output will contain list-cols.
#> • Use `values_fn = list` to suppress this warning.
#> • Use `values_fn = {summary_fun}` to summarise duplicates.
#> • Use the following dplyr code to identify duplicates.
#>   {data} %>%
#>   dplyr::group_by(id, year_h) %>%
#>   dplyr::summarise(n = dplyr::n(), .groups = "drop") %>%
#>   dplyr::filter(n > 1L)
#> # A tibble: 2 × 3
#>   id    h1        h2       
#>   <chr> <list>    <list>   
#> 1 A     <dbl [2]> <dbl [1]>
#> 2 B     <dbl [1]> <dbl [1]>

可以通过警告信息中的提示来检查可能存在的问题:

df |> 
  dplyr::group_by(id, year_h) |> 
  dplyr::summarise(n = dplyr::n(), .groups = "drop") |> 
  dplyr::filter(n > 1L)
#> # A tibble: 1 × 3
#>   id    year_h     n
#>   <chr> <chr>  <int>
#> 1 A     h1         2

总结

至此,我们快速学完了数据分析的全过程基础,已经可以应付很多的数据处理情况了。在这一节的学习中,我们学了数据的整理,这将帮助我们获得整洁的数据。另外,我们还学到了一些扩充数据的技巧,熟练掌握这些函数的使用将在我们以后实际遇到对应情况时,快速想到相应的解决措施。我们所有学习到的知识都应该在实践中将他们运用起来。(碎碎念:这几天虽然还在家房价,但都在帮老板干活,五天开了三次会,真累啊。但是学无止境,每天还是要完成一定的学习任务的。话说老板出差为什么不能带上我去玩呢?)

这个系列还未结束,后续将会就这些步骤展开更加详细的进阶介绍。

02-23 16:57