基于tidyr的长/宽数据转换

参考:https://r4ds.hadley.nz/data-tidy

Tidyr是tidyverse的核心包之一,其目标是帮助创建整洁的数据。整洁的数据是具有以下特征的数据:

Figure 1: 整洁数据的基本特征

1 加载包

这里的案例数据显示了以三种不同方式组织的相同数据。每个数据集都有相同的四个变量:country(国家)、year(年份)、population(总人口)和cases(结核病病例数),但每个数据集以不同的方式组织这些值。

table1
# A tibble: 6 × 4
  country      year  cases population
  <chr>       <dbl>  <dbl>      <dbl>
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
table2
# A tibble: 12 × 4
   country      year type            count
   <chr>       <dbl> <chr>           <dbl>
 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
table3
# A tibble: 6 × 3
  country      year rate             
  <chr>       <dbl> <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

table1中的数据符合 Figure 1 中的整洁数据规范。

2 pivot_longer():转换成长数据

这里我们以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>, …

在这个数据集中,每个观测(行)都是一首歌曲。前三列(“artist”、“track”和“date.entered”)是描述歌曲的变量。在此之后的76 列(“wk1”-“wk76”)描述了该歌曲在发行后每周的排名信息(仅在进入前100名时记录名次信息)。因此,对于“wk1”-“wk76”中的数据,所有的列名是一个变量(周数),每个单元格值则是另一个变量(每周的排名)。因此,这个数据集是不符合整洁数据的要求的。

下面,我们通过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, date.entered) 或 starts_with("wk") 来选择“wk1”到“wk76”列。

  • names_to:转换后的列的列名,即新变量名。这里我们将该变量命名为 “week” 。

  • values_to:指定单元格值所代表的变量的变量名。我们将该变量命名为 “rank”。⚠️注意”week”和”rank”加了引号。

现在,让我们聚焦生成的长数据。如果一首歌进入前 100 名的时间少于 76 周,会发生什么情况?以 2 Pac 的《Baby Don’t Cry》为例。上面的输出结果表明,这首歌在前 100 名中只停留了 7 周,其余的周数都是缺失值。这些缺失值其实并不代表未知观测值,而是转换后的长数据集的结构迫使它们存在,因此我们可以通过设置 values_drop_na = TRUE 来要求 pivot_longer()去掉它们:

billboard |> 
  pivot_longer(
    cols = starts_with("wk"), 
    names_to = "week", 
    values_to = "rank",
    values_drop_na = TRUE
  )
# A tibble: 5,307 × 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 2Ge+her The Hardest Part Of ... 2000-09-02   wk1      91
 9 2Ge+her The Hardest Part Of ... 2000-09-02   wk2      87
10 2Ge+her The Hardest Part Of ... 2000-09-02   wk3      92
# ℹ 5,297 more rows

注意到“week”目前为字符型变量,可以通过readr包中的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

现在,我们在一个变量中拥有了所有的周数,在另一个变量中拥有了所有的排名值,这样我们就可以很好地直观显示歌曲排名随时间的变化情况。代码如下,结果如 Figure 2 所示。我们可以看到,很少有歌曲能在前 100 名中停留 20 周以上。

billboard_longer |> 
  ggplot(aes(x = week, 
             y = rank, 
             group = track)) + 
  geom_line(alpha = 0.25) + 
  scale_y_reverse() +
  theme_bw()
Figure 2: 显示歌曲排名随时间变化的折线图

2.1 pivot_longer()的转换原理

假设我们有三个病人,id 分别为 A、B 和 C,我们为每个病人测量了两次血压。这里我们用在此前章节中已经介绍过的 tribble() 来创建这个数据:

df <- tribble(
  ~id,  ~bp1, ~bp2,
   "A",  100,  120,
   "B",  140,  115,
   "C",  120,  125
)

该数据集的“bp1”和“bp2”列不符合整洁数据的要求。因此,我们通过pivot_longer()将该数据转换成包含三个变量:id(已存在)、measurement(血压测定次数)和 value(血压值)的新数据:

df |> 
  pivot_longer(
    cols = bp1:bp2,
    names_to = "measurement",
    values_to = "value"
  )
# A tibble: 6 × 3
  id    measurement value
  <chr> <chr>       <dbl>
1 A     bp1           100
2 A     bp2           120
3 B     bp1           140
4 B     bp2           115
5 C     bp1           120
6 C     bp2           125

转换是如何进行的呢?如果我们逐列考虑,就会比较容易理解。如下图所示,在原始数据集中已经是变量的一列(id)的值需要重复,重复的次数等于需要转换的列数。这里我们需要转换的列是“bp1”和“bp2”,因此每个“id”需要重复两次。

旧列名将成为新变量的值,该变量的名称由 names_to 参数定义。

单元格值也会变成一个新变量的值,其名称由 values_to 定义。这些值将逐行填充。

2.2 包含多个变量信息的列名

更具挑战性的情况是,列名中包含了多个变量信息,而我们希望将这些信息分别存储在不同的新变量中。以 who2 数据集为例,该数据集由世界卫生组织收集,记录了肺结核诊断的相关信息:

Table 1: 肺结核病例信息-列名包含多个变量信息
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>, …
# 查看3:56的列名规则
colnames(who2)[3:56] %>% 
  str_split(
    pattern = "_", 
    simplify = T
    ) %>% 
  apply(MARGIN = 2, unique)
[[1]]
[1] "sp"  "sn"  "ep"  "rel"

[[2]]
[1] "m" "f"

[[3]]
[1] "014"  "1524" "2534" "3544" "4554" "5564" "65"  

可以看到,该数据的前两列“country”和“year”是正常的变量。剩余的56列,每一列的名称都由三个部分组成,中间用 “_” 分隔:

  • 第一部分为“sp/rel/ep”,代表采用的诊断方法;

  • 第二部分为“m/f” ,代表性别;

  • 第三部分为“014/1524/2534/3535/44/4554/5564/65”, 代表年龄范围(例如,014 代表 0-14岁)。

因此,在这种情况下,who2 数据中记录了六条变量信息:国家和年份(已列出);诊断方法、性别和年龄范围(包含在3-56列的列名中),以及该类别中的患者人数(单元格值)。为了将这六条变量信息转换到六个独立的列中,我们可以通过指定 pivot_longer() 中的 names_sep 参数,按照“_”分隔符将原始变量名分割成若干个字符串:

who2 |> 
  pivot_longer(
    cols = !(country:year),
    names_sep = "_", # 指定原始列名的分隔符
    names_to = c("diagnosis", "gender", "age"), 
    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 参数,通过正则表达式来实现上述效果。在这个案例中的数据转换过程参考如下示意图:

2.3 混合了变量名和变量取值的列名

Table 2: 家庭数据
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     

该数据集包含五个家庭的数据,每个家庭最多记录两个孩子的姓名(name_child1、name_child2)和出生日期(dob_child1、dob_child2)。仔细观察 Table 1Table 2 可以发现 :Table 1 中需要转换的列名均由不同变量的具体取值构成(如“sp_m_014”,我们就可以知道这一列对应的诊断方法为“sp”,性别为“m”,年龄段为0-14岁);而 Table 2 的列名既有变量的具体取值,如“child1”告诉我们这是编号为1的child,也有变量的名称,如“dob”(出生日期)和“name”(姓名)。

为了解决这个问题,我们同样需要根据“_”分隔符分割原始列名,然后向 names_to 提供新变量名。但由于列名混合了变量名和变量取值,我们难以一一对应新旧列名。因此,这时候我们使用特殊的”.value “字符让分割后的旧列名的第一个元素直接作为新变量的名称;分割后的旧列名的第二个元素(child1或child2)作为新的“child”变量的取值

household |> 
  pivot_longer(
    cols = !family, 
    names_sep = "_", 
    names_to = c(".value", "child"), 
    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

使用 names_to = c(".value", "num") 进行数据转换会将列名分成两部分:第一部分决定输出的列名(x 或 y),第二部分决定 num 列的值。见下面的示意图:

3 pivot_wider():转换成宽数据

pivot_wider() 可以通过增加列数和减少行数使数据集变宽。例如在重复测量数据中,一般而言我们会将每次观测作为一个个案,这时候一个对象多个时间点的观测数据分布在多行。这样的数据即为长数据,便于进行各种统计分析。但是如果你想了解每个对象的观测情况,就可以通过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
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>

4 拆分/合并列

4.1 unite():合并多列

unite(data, col, ..., sep, remove, na.rm) 可以将多列中的字符粘贴起来构成新的一列。其中:

  • data:目标数据集。

  • col:新列的名称。

  • ...:需要合并的列名(若用“:”连接则表示合并两列及之间的所有列)。

  • sep:指定连接符。

  • remove:是否移除原始列。

  • na.rm:如果为“True”,则在合并每个值之前将删除缺失值。

flights %>% 
  unite(
    col = "date", 
    sep = "/", 
    year, month, day, 
    na.rm = T
  )
# A tibble: 336,776 × 17
   date     dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay
   <chr>       <int>          <int>     <dbl>    <int>          <int>     <dbl>
 1 2013/1/1      517            515         2      830            819        11
 2 2013/1/1      533            529         4      850            830        20
 3 2013/1/1      542            540         2      923            850        33
 4 2013/1/1      544            545        -1     1004           1022       -18
 5 2013/1/1      554            600        -6      812            837       -25
 6 2013/1/1      554            558        -4      740            728        12
 7 2013/1/1      555            600        -5      913            854        19
 8 2013/1/1      557            600        -3      709            723       -14
 9 2013/1/1      557            600        -3      838            846        -8
10 2013/1/1      558            600        -2      753            745         8
# ℹ 336,766 more rows
# ℹ 10 more variables: carrier <chr>, flight <int>, tailnum <chr>,
#   origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
#   minute <dbl>, time_hour <dttm>

也可以用 str_c()str_glue() (见基于tidyr的字符串处理-拼接字符串)实现同样的效果:

flights %>% 
  mutate(
    date = str_c(year, month, day, sep = "/"),
    .before = year
  )
# A tibble: 336,776 × 20
   date      year month   day dep_time sched_dep_time dep_delay arr_time
   <chr>    <int> <int> <int>    <int>          <int>     <dbl>    <int>
 1 2013/1/1  2013     1     1      517            515         2      830
 2 2013/1/1  2013     1     1      533            529         4      850
 3 2013/1/1  2013     1     1      542            540         2      923
 4 2013/1/1  2013     1     1      544            545        -1     1004
 5 2013/1/1  2013     1     1      554            600        -6      812
 6 2013/1/1  2013     1     1      554            558        -4      740
 7 2013/1/1  2013     1     1      555            600        -5      913
 8 2013/1/1  2013     1     1      557            600        -3      709
 9 2013/1/1  2013     1     1      557            600        -3      838
10 2013/1/1  2013     1     1      558            600        -2      753
# ℹ 336,766 more rows
# ℹ 12 more variables: sched_arr_time <int>, arr_delay <dbl>, carrier <chr>,
#   flight <int>, tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>,
#   distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>
flights %>% 
  mutate(
    date = str_glue("{year}/{month}/{day}"),
    .before = year
  )

4.2 拆分列

tidyr 中,separate_wider_position()separate_wider_delim() 以及 separate_wider_regex() 可以将某一列根据分割符(separate_wider_delim())、固定宽度(separate_wider_position())或正则表达式(separate_wider_regex())拆分为多列。把这些函数中的“wider”替换成“longer”就构成了另外三个类似函数,用于将某一列根据分割符、固定宽度或正则表达式拆分为多行(不常用)。因为涉及到字串的处理以及正则表达式,我们在基于tidyr的字符串处理-拼接字符串中对这些函数进行了详细介绍。


R version 4.3.3 (2024-02-29)
Platform: aarch64-apple-darwin20 (64-bit)
Running under: macOS Sonoma 14.3.1

Matrix products: default
BLAS:   /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRblas.0.dylib 
LAPACK: /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRlapack.dylib;  LAPACK version 3.11.0

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

time zone: Asia/Shanghai
tzcode source: internal

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] nycflights13_1.0.2 lubridate_1.9.3    forcats_1.0.0      stringr_1.5.1     
 [5] dplyr_1.1.4        purrr_1.0.2        readr_2.1.5        tidyr_1.3.1       
 [9] tibble_3.2.1       ggplot2_3.5.0      tidyverse_2.0.0   

loaded via a namespace (and not attached):
 [1] gtable_0.3.4      jsonlite_1.8.8    compiler_4.3.3    tidyselect_1.2.0 
 [5] scales_1.3.0      yaml_2.3.8        fastmap_1.1.1     R6_2.5.1         
 [9] generics_0.1.3    knitr_1.45        htmlwidgets_1.6.4 munsell_0.5.0    
[13] pillar_1.9.0      tzdb_0.4.0        rlang_1.1.3       utf8_1.2.4       
[17] stringi_1.8.3     xfun_0.42         timechange_0.3.0  cli_3.6.2        
[21] withr_3.0.0       magrittr_2.0.3    digest_0.6.34     grid_4.3.3       
[25] rstudioapi_0.15.0 hms_1.1.3         lifecycle_1.0.4   vctrs_0.6.5      
[29] evaluate_0.23     glue_1.7.0        codetools_0.2-19  fansi_1.0.6      
[33] colorspace_2.1-0  rmarkdown_2.25    tools_4.3.3       pkgconfig_2.0.3  
[37] htmltools_0.5.7