【问题标题】:conditionally transpose select rows using tidyverse使用 tidyverse 有条件地转置选择行
【发布时间】:2019-09-27 20:40:08
【问题描述】:

我有一个正在使用的数据集,我正在尝试使用 tidyverse 对其进行重塑。

发件人:

|Name |eval   |test |type      | score|
|:----|:------|:----|:---------|-----:|
|John |first  |1    |pretest   |    10|
|John |first  |1    |posttest  |    15|
|John |first  |2    |pretest   |    20|
|John |first  |2    |posttest |    30|
|John |second |1    |pretest   |    35|
|John |second |1    |posttest  |    50|
|John |second |2    |pretest   |     5|
|John |second |2    |posttest |    10|
|Jane |first  |1    |pretest   |    40|
|Jane |first  |1    |posttest  |    20|
|Jane |first  |2    |pretest   |    10|
|Jane |first  |2    |posttest |    20|

收件人:

|Name |eval   |new_name      | pre_test| post_test|
|:----|:------|:-------------|--------:|---------:|
|John |first  |John_first_1  |       10|        15|
|John |first  |John_first_2  |       20|        30|
|John |second |John_second_1 |       35|        50|
|John |second |John_second_2 |        5|        10|
|Jane |first  |Jane_first_1  |       40|        20|
|Jane |first  |Jane_first_2  |       10|        20|
  • 尝试执行 group_by 以分组名称、评估和测试,以便每个组基本上是特定人的 pre_test 与 post_test。

  • 还尝试在名称、评估、测试和类型上使用 unite。但是,如果我在此之后进行 spread,那么每个唯一名称最终都会成为多个列。

  • 还尝试先对 Name 进行 unite,然后先进行 eval、test,然后使用 key=(new united name) 和 value = 进行 spread值,但输出不是我想要的

我知道可以编写一个循环函数来获取所有其他值并放入一个新列,但我正在尝试看看是否有 tidyverse 方法来解决这个问题。

谢谢!!

library(tidyverse)
Name <- c('John', 'John', 'John', 'John',
              'John', 'John', 'John', 'John',
              'Jane', 'Jane', 'Jane', 'Jane')
eval <- c('first', 'first', 'first', 'first',
          'second', 'second', 'second', 'second',
          'first', 'first', 'first', 'first')
test <- c('1', '1', '2', '2',
          '1', '1', '2', '2',
          '1', '1', '2', '2')
type <- c('pretest', 'posttest', 'pretest', 'posttest',
          'pretest', 'posttest', 'pretest', 'posttest',
          'pretest', 'posttest', 'pretest', 'posttest')
score <- c(10, 15, 20, 30, 35, 50, 5, 10, 40, 20, 10, 20)
df <- data.frame(Name, eval, test, type, score)

df %>%
  unite(temp, Name, eval, test) %>%
  spread(key=type, value=score)

编辑以显示 akrun 的代码处理的原始表格 来自:

|Name |eval   |test |type      | score|
|:----|:------|:----|:---------|-----:|
|John |first  |1    |pretest   |    10|
|John |first  |1    |posttest  |    15|
|John |first  |2    |pretest   |    20|
|John |first  |2    |postttest |    30|
|John |second |1    |pretest   |    35|
|John |second |1    |posttest  |    50|
|John |second |2    |pretest   |     5|
|John |second |2    |postttest |    10|
|Jane |first  |1    |pretest   |    40|
|Jane |first  |1    |posttest  |    20|
|Jane |first  |2    |pretest   |    10|
|Jane |first  |2    |postttest |    20|

【问题讨论】:

    标签: r tidyverse


    【解决方案1】:

    我们可以替换'type'列中的多个't'使其相同,然后使用unite指定remove = FALSE以保留初始列和spread

    library(dplyr)
    library(tidyr)
    library(stringr)
    df %>% 
       mutate(type = str_replace(type, "t{2,}", "t")) %>%
       unite(new_name, Name, eval, test, remove = FALSE) %>% 
       spread(type, score)
    #       new_name Name   eval test postest pretest
    #1  Jane_first_1 Jane  first    1      20      40
    #2  Jane_first_2 Jane  first    2      20      10
    #3  John_first_1 John  first    1      15      10
    #4  John_first_2 John  first    2      30      20
    #5 John_second_1 John second    1      50      35
    #6 John_second_2 John second    2      10       5
    

    在新版本tidyr_1.0.0中,引入了pivot_wider,它可以作为spread的更通用版本(将来会被弃用)。因此,不要使用末尾的 spread 行,而是使用

     ...%>%
        pivot_wider(names_from = type, values_from = score)
    

    【讨论】:

    • 实际上只是在编辑错字,只是使用spread 方法解决了这个问题。不知道pivot_wider 方法。谢谢!
    【解决方案2】:

    比如......

    data <- tibble(
      Name = c(rep("John", 8), rep("Jane", 4)),
      eval = c(rep("first", 4), rep("second", 4), rep("first", 4)),
      type = rep(c("pretest", "posttest"), 6),
      score = c(10, 15, 20, 30, 35, 50, 5, 10, 40, 20, 10, 20)
    )
    
    data %>% 
      group_by(Name, eval, type) %>% 
      mutate(num = 1:n(),
             new_name = str_c(Name, "_", eval, "_", num)) %>% 
      ungroup()  %>% 
      dplyr::select(new_name, type, score) %>% 
      spread(type, score) 
    

    产量:

    # A tibble: 6 x 3
      new_name      posttest pretest
      <chr>            <dbl>   <dbl>
    1 Jane_first_1        20      40
    2 Jane_first_2        20      10
    3 John_first_1        15      10
    4 John_first_2        30      20
    5 John_second_1       50      35
    6 John_second_2       10       5
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-04-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多