美文网首页
10.因子(factor)

10.因子(factor)

作者: denghb001 | 来源:发表于2022-01-06 09:28 被阅读0次

    1 简介

    在 R 中,因子用于处理分类变量,即具有一组固定且已知的可能值的变量。当您想以非字母顺序显示字符向量时,它们也很有用。

    1.1 加载包

    为了处理因子,我们将使用forcats包,它是 tidyverse 的核心部分。

    library(tidyverse)
    

    2 因子的创建

    假设有一个记录月份的变量:

    x1 <- c("Dec", "Apr", "Jan", "Mar")
    

    使用字符串记录这个变量有两个问题:

    1. 最多只有十二个月,而且有可能出现打字错误:

      x2 <- c("Dec", "Apr", "Jam", "Mar")
      
    2. 排序的结果没有用处:

      sort(x1)
      #> [1] "Apr" "Dec" "Jan" "Mar"
      

    可以使用因子来解决这两个问题。要创建因子,必须首先创建一个有效等级列表:

    month_levels <- c(
      "Jan", "Feb", "Mar", "Apr", "May", "Jun", 
      "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
    )
    

    现在您可以创建一个因子:

    y1 <- factor(x1, levels = month_levels)
    y1
    #> [1] Dec Apr Jan Mar
    #> Levels: Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
    sort(y1)
    #> [1] Jan Mar Apr Dec
    #> Levels: Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
    

    任何不在集合中的值都将转换为 NA:

    y2 <- factor(x2, levels = month_levels)
    y2
    #> [1] Dec  Apr  <NA> Mar 
    #> Levels: Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
    

    如果你想要一个警告,你可以使用readr::parse_factor()

    y2 <- parse_factor(x2, levels = month_levels)
    #> Warning: 1 parsing failure.
    #> row col           expected actual
    #>   3  -- value in level set    Jam
    

    如果省略了等级,它们将按字母顺序从数据中获得等级:

    factor(x1)
    #> [1] Dec Apr Jan Mar
    #> Levels: Apr Dec Jan Mar
    

    有时,您希望等级的顺序与数据中首次出现的顺序相匹配。您可以在创建因子时通过将级别设置为unique(x)或事后使用fct_inorder()

    f1 <- factor(x1, levels = unique(x1))
    f1
    #> [1] Dec Apr Jan Mar
    #> Levels: Dec Apr Jan Mar
    
    f2 <- x1 %>% factor() %>% fct_inorder()
    f2
    #> [1] Dec Apr Jan Mar
    #> Levels: Dec Apr Jan Mar
    

    如果您需要直接访问因子的等级,可以使用levels()

    levels(f2)
    #> [1] "Dec" "Apr" "Jan" "Mar"
    

    3 常规信息

    接下来我们将了解forcats::gss_cat。这是来自General Social Survey的数据样本,这是一项由芝加哥大学独立研究组织 NORC 进行的长期美国调查。该调查包含数千个问题,因此我选择了gss_cat一些问题来说明您在处理因子时会遇到的一些问题。

    gss_cat
    #> # A tibble: 21,483 x 9
    #>    year marital      age race  rincome    partyid     relig     denom    tvhours
    #>   <int> <fct>      <int> <fct> <fct>      <fct>       <fct>     <fct>      <int>
    #> 1  2000 Never mar…    26 White $8000 to … Ind,near r… Protesta… Souther…      12
    #> 2  2000 Divorced      48 White $8000 to … Not str re… Protesta… Baptist…      NA
    #> 3  2000 Widowed       67 White Not appli… Independent Protesta… No deno…       2
    #> 4  2000 Never mar…    39 White Not appli… Ind,near r… Orthodox… Not app…       4
    #> 5  2000 Divorced      25 White Not appli… Not str de… None      Not app…       1
    #> 6  2000 Married       25 White $20000 - … Strong dem… Protesta… Souther…      NA
    #> # … with 21,477 more rows
    

    当因子存储在列中时,您无法那么容易地看到它们的水平。可通过count()查看:

    gss_cat %>%
      count(race)
    #> # A tibble: 3 x 2
    #>   race      n
    #>   <fct> <int>
    #> 1 Other  1959
    #> 2 Black  3129
    #> 3 White 16395
    

    或者使用条形图:

    ggplot(gss_cat, aes(race)) +
      geom_bar()
    
    image

    默认情况下,ggplot2 将删除没有任何值的等级。但是也可以强制显示它们:

    ggplot(gss_cat, aes(race)) +
      geom_bar() +
      scale_x_discrete(drop = FALSE)
    
    image

    这些级别代表在此数据集中根本没有出现的有效值。

    在处理因子时,两个最常见的操作是更改级别的顺序和更改级别的值。

    4 修改因子顺序

    在可视化中更改因子级别的顺序通常很有用。例如,假设您想探索不同宗教每天平均看电视上小时数:

    relig_summary <- gss_cat %>%
      group_by(relig) %>%
      summarise(
        age = mean(age, na.rm = TRUE),
        tvhours = mean(tvhours, na.rm = TRUE),
        n = n()
      )
    #> `summarise()` ungrouping output (override with `.groups` argument)
    
    ggplot(relig_summary, aes(tvhours, relig)) + geom_point()
    
    image

    从整体上很难理解这个图形。我们可以通过使用fct_reorder()重新排序relig的级别来改进它。fct_reorder()需要三个参数:

    • f,要修改其等级的因子。
    • x,一个数字向量,用它来重新排序级别。
    • 可选,如果funx每个值有多个值,则使用的函数 f。默认值为median
    ggplot(relig_summary, aes(tvhours, fct_reorder(relig, tvhours))) +
      geom_point()
    
    image

    重新排序宗教可以更容易地看到,“Don't know”类别的人看的电视多得多,而印度教和其他东方宗教的看的少得多。

    开始进行更复杂的转换时,我建议将它们移出aes()并且移入单独的mutate()步骤。例如,您可以将上面的图重写为:

    relig_summary %>%
      mutate(relig = fct_reorder(relig, tvhours)) %>%
      ggplot(aes(tvhours, relig)) +
        geom_point()
    

    如果我们创建一个类似的图来查看平均年龄随报告收入水平的变化会怎样?

    rincome_summary <- gss_cat %>%
      group_by(rincome) %>%
      summarise(
        age = mean(age, na.rm = TRUE),
        tvhours = mean(tvhours, na.rm = TRUE),
        n = n()
      )
    #> `summarise()` ungrouping output (override with `.groups` argument)
    
    ggplot(rincome_summary, aes(age, fct_reorder(rincome, age))) + geom_point()
    
    image

    在这里,随意排序级别不是一个好主意!那是因为rincome已经有一个我们不应该乱动的原则性命令。fct_reorder()为任意等级排序的因素预留。

    但是,将“Not applicable”拉到其他特殊级别的前面确实是有意义的。您可以使用fct_relevel(). 它需要一个因子 ,f是您想要移动到行前面的任意数量的级别。

    ggplot(rincome_summary, aes(age, fct_relevel(rincome, "Not applicable"))) +
      geom_point()
    
    image

    为什么认为“Not applicable”的平均年龄如此之高?

    当您为绘图上的线条着色时,另一种类型的重新排序很有用。fct_reorder2()yx最大值关联的值对因子重新排序。这使绘图更易于阅读,因为线条颜色与图例对齐。

    by_age <- gss_cat %>%
      filter(!is.na(age)) %>%
      count(age, marital) %>%
      group_by(age) %>%
      mutate(prop = n / sum(n))
    
    ggplot(by_age, aes(age, prop, colour = marital)) +
      geom_line(na.rm = TRUE)
    
    ggplot(by_age, aes(age, prop, colour = fct_reorder2(marital, age, prop))) +
      geom_line() +
      labs(colour = "marital")
    
    image image

    最后,对于条形图,可以使用fct_infreq()递增频率对级别进行排序:这是最简单的重新排序类型,因为它不需要任何额外的变量。您可能希望与fct_rev().

    gss_cat %>%
      mutate(marital = marital %>% fct_infreq() %>% fct_rev()) %>%
      ggplot(aes(marital)) +
        geom_bar()
    
    image

    5 修改因子级别

    比更改级别更强大的是更改它们的值。这使您可以直接定义想要的级别。最通用和最强大的工具是fct_recode(). 它允许您重新编码或更改每个级别的值。例如,使用gss_cat$partyid

    gss_cat %>% count(partyid)
    #> # A tibble: 10 x 2
    #>   partyid                n
    #>   <fct>              <int>
    #> 1 No answer            154
    #> 2 Don't know             1
    #> 3 Other party          393
    #> 4 Strong republican   2314
    #> 5 Not str republican  3032
    #> 6 Ind,near rep        1791
    #> # … with 4 more rows
    

    这些级别简洁且不一致。让我们将它们调整得更长,并使用平行结构。

    gss_cat %>%
      mutate(partyid = fct_recode(partyid,
        "Republican, strong"    = "Strong republican",
        "Republican, weak"      = "Not str republican",
        "Independent, near rep" = "Ind,near rep",
        "Independent, near dem" = "Ind,near dem",
        "Democrat, weak"        = "Not str democrat",
        "Democrat, strong"      = "Strong democrat"
      )) %>%
      count(partyid)
    #> # A tibble: 10 x 2
    #>   partyid                   n
    #>   <fct>                 <int>
    #> 1 No answer               154
    #> 2 Don't know                1
    #> 3 Other party             393
    #> 4 Republican, strong     2314
    #> 5 Republican, weak       3032
    #> 6 Independent, near rep  1791
    #> # … with 4 more rows
    

    fct_recode() 将保留未明确提及的级别,如果引用了不存在的级别,则会警告您。

    要合并组,您可以将多个旧级别分配给同一个新级别:

    gss_cat %>%
      mutate(partyid = fct_recode(partyid,
        "Republican, strong"    = "Strong republican",
        "Republican, weak"      = "Not str republican",
        "Independent, near rep" = "Ind,near rep",
        "Independent, near dem" = "Ind,near dem",
        "Democrat, weak"        = "Not str democrat",
        "Democrat, strong"      = "Strong democrat",
        "Other"                 = "No answer",
        "Other"                 = "Don't know",
        "Other"                 = "Other party"
      )) %>%
      count(partyid)
    #> # A tibble: 8 x 2
    #>   partyid                   n
    #>   <fct>                 <int>
    #> 1 Other                   548
    #> 2 Republican, strong     2314
    #> 3 Republican, weak       3032
    #> 4 Independent, near rep  1791
    #> 5 Independent            4119
    #> 6 Independent, near dem  2499
    #> # … with 2 more rows
    

    如果您想折叠很多级别,可以使用fct_collapse()。 对于每个新变量,您可以提供旧级别的向量:

    gss_cat %>%
      mutate(partyid = fct_collapse(partyid,
        other = c("No answer", "Don't know", "Other party"),
        rep = c("Strong republican", "Not str republican"),
        ind = c("Ind,near rep", "Independent", "Ind,near dem"),
        dem = c("Not str democrat", "Strong democrat")
      )) %>%
      count(partyid)
    #> # A tibble: 4 x 2
    #>   partyid     n
    #>   <fct>   <int>
    #> 1 other     548
    #> 2 rep      5346
    #> 3 ind      8409
    #> 4 dem      7180
    

    有时,您只想将所有组放在一起,以简化绘图或表格。使用fct_lump()

    gss_cat %>%
      mutate(relig = fct_lump(relig)) %>%
      count(relig)
    #> # A tibble: 2 x 2
    #>   relig          n
    #>   <fct>      <int>
    #> 1 Protestant 10846
    #> 2 Other      10637
    

    默认行为是逐渐将最小的组混在一起,确保聚合仍然是最小的组。在这种情况下,它不是很有帮助:因为这项调查中的大多数美国人都是新教徒。

    相反,我们可以使用n参数来指定我们要保留的组数(不包括其他组):

    gss_cat %>%
      mutate(relig = fct_lump(relig, n = 10)) %>%
      count(relig, sort = TRUE) %>%
      print(n = Inf)
    #> # A tibble: 10 x 2
    #>    relig                       n
    #>    <fct>                   <int>
    #>  1 Protestant              10846
    #>  2 Catholic                 5124
    #>  3 None                     3523
    #>  4 Christian                 689
    #>  5 Other                     458
    #>  6 Jewish                    388
    #>  7 Buddhism                  147
    #>  8 Inter-nondenominational   109
    #>  9 Moslem/islam              104
    #> 10 Orthodox-christian         95
    

    相关文章

      网友评论

          本文标题:10.因子(factor)

          本文链接:https://www.haomeiwen.com/subject/qdgqcrtx.html