【问题标题】:How to filter within a pivot_longer如何在 pivot_longer 中过滤
【发布时间】:2021-05-13 06:46:58
【问题描述】:

我正在使用一个数据集,其中我需要对一系列列进行透视,但是我应该过滤掉每个组中所有为 NULL 的记录。 下面是一个例子

    library(tidyverse)

courses_col = c("Science",     "Mathematic",    "French",         "Biology")

mapping <- tibble(
    courses  = courses_col,
    level =  c("aaaa", "aaaa", "bbbb", "cccc")
)

score <- tibble(
    name = c("Bob", "Simon", "Albert", "Marc"),
    French = c("A", "A", "B", "C"),
    Science = c("A", "B", NA, "C"),
    Mathematic = c("A", "A", NA, NA),
    Biology = c("A", "B", NA, "B"),
    score = c(12, 14, 15, 12)
)


score %>%
    select(name, Science, Mathematic, score) %>%
    filter(!is.na(Science) & !is.na(Mathematic)) %>%
    summarise(ratio = median(score))

score %>%
    pivot_longer(
        cols = courses_col,
        names_to = "courses",
        values_to = "grade"
    ) %>%
    left_join(mapping, by = "courses") %>%
    filter(!is.na(grade)) %>%
    summarise(
        ratio = median(score)
    ) 

对于第一个代码,我得到与课程“科学”和“数学”相对应的组“aaaa”的中值 13 - 请注意,如果两列都是 NA,我将手动过滤 NA 值。

但是,当我旋转数据时,我失去了为组应用过滤器的可能性。第二个示例产生的中位数为 12,因为它丢弃了所有 NA。

我应该如何解决这个问题?

【问题讨论】:

  • 我不清楚你想要的输出应该是什么样子。你能提供吗?

标签: r pivot tidyverse tidyr


【解决方案1】:

@迈克尔。

当您pivot_longer 数据集时,您增加了得分列 的值的数量。记住 Median 是数据集的中间值。

所以,在你的第一个例子中:

score %>%
select(name, Science, Mathematic, score) %>%
filter(!is.na(Science) & !is.na(Mathematic)) %>%
summarise(ratio = median(score))

输出将是:

name French Science Mathematic Biology score
Bob A A A A 12
Simon A B A B 14

在这个例子中,我们要计算中位数:

(12 + 14) / 2 = 13 --> 你找到的结果。

但是,在第二个例子中:

score %>%
pivot_longer(
    cols = courses_col,
    names_to = "courses",
    values_to = "grade"
) %>%
left_join(mapping, by = "courses") %>%
filter(!is.na(grade)) %>%
summarise(
    ratio = median(score)
) 

输出是:

name score courses grade level
Bob 12 Science A aaaa
Bob 12 Mathematic A aaaa
Bob 12 French A bbbb
Bob 12 Biology A cccc
Simon 14 Science B aaaa
Simon 14 Mathematic A aaaa
Simon 14 French A bbbb
Simon 14 Biology B cccc
Albert 15 French B cccc
Marc 12 Science C aaaa
Marc 12 French C bbbb
Marc 12 Biology B cccc

在此示例中,您将观察次数增加到列 score。要计算这种情况的中位数,我们必须对这些值进行排序,取中间的两个数字,相加并除以 2,就像我们之前所做的那样。 p>

所以,我们有:

Number Number of Cases
12 7
14 4
15 1
Total: 12

让我们对数字进行排序以知道它们在数据集的中间:

12、12、12、12、12、12、12、14、14、14、14、15

好吧,排序我们看到中间两个数字的数字是:

12、12、12、12、12、12、12、14、14、14、14、15

因此,让我们计算第二个示例的中位数:

(12 + 12) / 12 = 12 --> 不同的中位数。

为了解决这个问题,我将数据集恢复为原始形状,添加了一些新列:

score %>%  pivot_longer(
cols = courses_col,
names_to = "courses",
values_to = "grade") %>%
left_join(mapping, by = "courses") %>%
pivot_wider(names_from = courses, values_from = c(grade, level)) %>%
summarise(ratio = median(score))

要重命名我使用的列:

col.names <- c('name','score','Science', 'Mathematic','French','Biology', 'level_1','level_2','level_3','level_4')
colnames(score) <- col.names

希望这对您有所帮助。

如果您想了解有关 Median 的更多信息,请点击链接:purplemath.com/modules/meanmode.htm

【讨论】:

    【解决方案2】:

    要在旋转后完成此操作,您需要使用 group_byfilter

    score %>% 
      pivot_longer(
        cols = courses_col,
        names_to = "courses",
        values_to = "grade"
      ) %>%
      left_join(mapping, by = "courses") %>%
      dplyr::group_by(name) %>%
      dplyr::filter(sum(is.na(grade) & courses %in% c("Science", "Mathematic")) < 2) %>% 
      dplyr::ungroup() 
    
      name  score courses    grade level
       <chr> <dbl> <chr>      <chr> <chr>
     1 Bob      12 Science    A     aaaa 
     2 Bob      12 Mathematic A     aaaa 
     3 Bob      12 French     A     bbbb 
     4 Bob      12 Biology    A     cccc 
     5 Simon    14 Science    B     aaaa 
     6 Simon    14 Mathematic A     aaaa 
     7 Simon    14 French     A     bbbb 
     8 Simon    14 Biology    B     cccc 
     9 Marc     12 Science    C     aaaa 
    10 Marc     12 Mathematic NA    aaaa 
    11 Marc     12 French     C     bbbb 
    12 Marc     12 Biology    B     cccc 
    

    【讨论】:

    • 谢谢,但是,这全部不适用,我真正需要的是一个过滤器,适用于所有分组列都是 NA 的情况
    • 在您的示例中,哪些分组列都是NA?您的第一个输出是一个 1x1 tibble,其值为 14,我看不到任何分组变量,NA 仅存在于 ScienceMathematic 中的一个 name
    • 你的分组变量是什么?当所有FrenchScienceMathematicBiology 都存在NA 时,您是否要删除整行?
    • 该组在mapping 数据框中定义。例如,在分组“aaaa”中,如果我在 Science 和 Mathematic 中都看到 NA,则必须删除整行。在示例中,您可以看到 Albert 的行被过滤掉了,但 Marc 的行没有被过滤掉。希望有意义
    • 分组“aaaa”只是科学,不是数学和科学。
    【解决方案3】:

    我们可以使用values_drop_na

    library(dplyr)
    library(tidyr)
    score %>%
      pivot_longer(
         cols = courses_col,
         names_to = "courses",
         values_to = "grade", values_drop_na = TRUE
     ) %>%
      left_join(mapping) %>% 
      summarise(ratio = median(score))
    

    【讨论】:

    • 嗨,谢谢,但是,与上一个答案类似,这会删除每个 NA,在这种情况下,我只想删除每个组的所有列都存在的 NA(注意过滤器 & AND在第一个例子中)
    • @Michael 在你的例子中,没有这样的情况
    • 也许刷新页面,我用这个细节更新了示例
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-20
    • 1970-01-01
    • 1970-01-01
    • 2019-07-23
    • 1970-01-01
    相关资源
    最近更新 更多