【问题标题】:Separate a column in dataframe where each observation can have multiple concurrent values在数据框中分隔一列,其中每个观察可以有多个并发值
【发布时间】:2016-08-18 07:20:03
【问题描述】:

我相信我的问题既是关于整理杂乱数据的最佳实践,也是关于整理杂乱数据的问题。

以下是数据框 lang.df 的摘录,这是一个全校学生数据集。 Langauge.Home 列表示家长对问题的回答: “你在家说什么语言?”

> lang.df
   Nationality             Language.Home
1           HK                  Mandarin
2       German   Mandarin/English/German
3        Saudi                    Arabic
4    Norwegian                 Norwegian
5           UK                   English
6           HK Mandarin/ Min Nan dialect
7   Australian                  Mandarin
8           HK                  Mandarin
9    Brazilian        Portuguese/English
10      Indian             Hindi/English

对我来说很明显,这是获取这些信息的糟糕方式以及存储信息的糟糕方式,但我的工作是使用我拥有的数据。

结果

我想探讨某些母语可能对成就产生的影响。我需要的是能够通过在家说的一种语言(例如在家说英语的学生)进行子集化。

为此,看来我必须使用 dplyr 的 separate()Language@home 列分成三个 ("language.home1", "language.home2", "language.home3")。为我创建的新列中的每个唯一值(即语言)创建一个新列

流程

以下是我尝试有效地执行上述操作

library(dplyr)
library(tidyr)

#separate Langauge.Home into three new columns
lang.df <- lang.df %>% separate(Language.Home,
        c("language.home1", "language.home2", "language.home3"),
        sep = "/",
        remove = FALSE)

#find distinct languages & remove NAs
langs <- unique(c(lang.df$language.home1,
    lang.df$language.home2,
    lang.df$language.home3))
langs <- langs[!is.na(langs)]

#create boolean column for each unique language in new columns
for (i in langs) {
lang.df[,paste(i)] <- grepl(i, lang.df$Language.Home) 
}

问题

  1. 这种情况叫什么?我试图查看tidyr 文档和此处的 SO 但找不到任何相关信息。
  2. 有没有比我所做的更优雅的转换编码方式?
  3. 什么是最佳实践
    • 获取此数据(以更改未来的数据输入流程)
    • 从统计角度处理这种情况

提前感谢您的帮助。我现在只断断续续地使用 R 大约一年,这是我的第一篇 SO 帖子。尽可能多地给我反馈!

数据

lang.df <- structure(list(Nationality = structure(c(4L, 3L, 7L, 6L, 8L, 
4L, 1L, 4L, 2L, 5L), .Label = c("Australian", "Brazilian", "German", 
"HK", "Indian", "Norwegian", "Saudi", "UK"), class = "factor"), 
`Language.Home` = structure(c(4L, 6L, 1L, 7L, 2L, 5L, 4L, 
4L, 8L, 3L), .Label = c("Arabic", "English", "Hindi/English", 
"Mandarin", "Mandarin/ Min Nan dialect", "Mandarin/English/German", 
"Norwegian", "Portuguese/English"), class = "factor")), row.names = c(NA, 
10L), .Names = c("Nationality", "Language.Home"), class = "data.frame")

【问题讨论】:

  • 也可以试试:cSplit_e(lang.df, "Language.Home", "/", type = "character", fill = 0).

标签: r dplyr tidyr


【解决方案1】:

我们可以使用splitstackshape 中的cSplit 使用分隔符/ 拆分“Language.Home”并将其转换为long 格式。

library(splitstackshape)
library(data.table)
dt <- cSplit(lang.df, "Language.Home", "/", "long")

然后,使用dcast 将“长”转换为“宽”

dcast(dt, Nationality~Language.Home, fun.aggregate = function(x) length(x)>0)

注意:有重复的“国籍”行,所以上面会将共同的元素组合在一起。将它们组合在一起可能会更好。

如果我们需要基于每一行的逻辑列(不考虑相似的“国籍”)

 dcast(cSplit(setDT(lang.df, keep.rownames=TRUE), "Language.Home",
   "/", "long"), rn +Nationality ~Language.Home, function(x) length(x) >0)

或者另一个选项是 mtabulate from qdapTools 在将“Language.Home”拆分为 / 之后。

 library(qdapTools)
 cbind(lang.df, !!(mtabulate(setNames(strsplit(as.character(lang.df$Language.Home), 
                 "/"), lang.df$Nationality))))
#   Nationality             Language.Home  Min Nan dialect Arabic English German Hindi Mandarin Norwegian Portuguese
#1           HK                  Mandarin            FALSE  FALSE   FALSE  FALSE FALSE     TRUE     FALSE      FALSE
#2       German   Mandarin/English/German            FALSE  FALSE    TRUE   TRUE FALSE     TRUE     FALSE      FALSE
#3        Saudi                    Arabic            FALSE   TRUE   FALSE  FALSE FALSE    FALSE     FALSE      FALSE
#4    Norwegian                 Norwegian            FALSE  FALSE   FALSE  FALSE FALSE    FALSE      TRUE      FALSE
#5           UK                   English            FALSE  FALSE    TRUE  FALSE FALSE    FALSE     FALSE      FALSE
#6           HK Mandarin/ Min Nan dialect             TRUE  FALSE   FALSE  FALSE FALSE     TRUE     FALSE      FALSE
#7   Australian                  Mandarin            FALSE  FALSE   FALSE  FALSE FALSE     TRUE     FALSE      FALSE
#8           HK                  Mandarin            FALSE  FALSE   FALSE  FALSE FALSE     TRUE     FALSE      FALSE
#9    Brazilian        Portuguese/English            FALSE  FALSE    TRUE  FALSE FALSE    FALSE     FALSE       TRUE
#10      Indian             Hindi/English            FALSE  FALSE    TRUE  FALSE  TRUE    FALSE     FALSE      FALSE

【讨论】:

  • 这正是我想要的;谢谢,@akrun!你能告诉我什么时候最好用长格式吗?也供我自己将来参考:this r bloggers post 是我一直在寻找的东西
  • @AndersSwanson 感谢您的反馈。转换为长格式取决于您要执行的分析类型。如果你正在用 ggplot 做一些图形,也许长格式是你想要做的。
【解决方案2】:

获取长格式的一种简单方法是使用tidyr::unnest()

library(dplyr)
library(tidyr)
library(stringr)

lang.df %>% 
  mutate(Language.Home = str_split(Language.Home, "/")) %>% 
  unnest()
#>    Nationality    Language.Home
#> 1           HK         Mandarin
#> 2       German         Mandarin
#> 3       German          English
#> 4       German           German
#> 5        Saudi           Arabic
#> 6    Norwegian        Norwegian
#> 7           UK          English
#> 8           HK         Mandarin
#> 9           HK  Min Nan dialect
#> 10  Australian         Mandarin
#> 11          HK         Mandarin
#> 12   Brazilian       Portuguese
#> 13   Brazilian          English
#> 14      Indian            Hindi
#> 15      Indian          English

【讨论】:

    【解决方案3】:

    这是一个基本方法,总共只有几行

    lang.df <- structure(list(Nationality = structure(c(4L, 3L, 7L, 6L, 8L, 4L, 1L, 4L, 2L, 5L), .Label = c("Australian", "Brazilian", "German", "HK", "Indian", "Norwegian", "Saudi", "UK"), class = "factor"), `Language.Home` = structure(c(4L, 6L, 1L, 7L, 2L, 5L, 4L, 4L, 8L, 3L), .Label = c("Arabic", "English", "Hindi/English", "Mandarin", "Mandarin/ Min Nan dialect", "Mandarin/English/German", "Norwegian", "Portuguese/English"), class = "factor")), row.names = c(NA, 10L), .Names = c("Nationality", "Language.Home"), class = "data.frame")
    

    第二部分:新的数据框,每种语言分成不同的列并按顺序标记

    dd <- read.table(text = gsub('/\\s*', ';', lang.df$Language.Home),
                     sep = ';', na.strings = '', fill = TRUE, as.is = TRUE,
                     col.names = paste0('lang.home', 1:3))
    #      lang.home1      lang.home2 lang.home3
    #   1    Mandarin            <NA>       <NA>
    #   2    Mandarin         English     German
    #   3      Arabic            <NA>       <NA>
    #   4   Norwegian            <NA>       <NA>
    #   5     English            <NA>       <NA>
    #   6    Mandarin Min Nan dialect       <NA>
    #   7    Mandarin            <NA>       <NA>
    #   8    Mandarin            <NA>       <NA>
    #   9  Portuguese         English       <NA>
    #  10       Hindi         English       <NA>
    

    第三部分:每种独特语言的逻辑指标

    lang <- na.omit(sort(unique(unlist(dd))))
    idx <- `colnames<-`(t(apply(dd, 1, function(x) lang %in% x)), lang)
    
    #       Arabic English German Hindi Mandarin Min Nan dialect Norwegian Portuguese
    #  [1,]  FALSE   FALSE  FALSE FALSE     TRUE           FALSE     FALSE      FALSE
    #  [2,]  FALSE    TRUE   TRUE FALSE     TRUE           FALSE     FALSE      FALSE
    #  [3,]   TRUE   FALSE  FALSE FALSE    FALSE           FALSE     FALSE      FALSE
    #  [4,]  FALSE   FALSE  FALSE FALSE    FALSE           FALSE      TRUE      FALSE
    #  [5,]  FALSE    TRUE  FALSE FALSE    FALSE           FALSE     FALSE      FALSE
    #  [6,]  FALSE   FALSE  FALSE FALSE     TRUE            TRUE     FALSE      FALSE
    #  [7,]  FALSE   FALSE  FALSE FALSE     TRUE           FALSE     FALSE      FALSE
    #  [8,]  FALSE   FALSE  FALSE FALSE     TRUE           FALSE     FALSE      FALSE
    #  [9,]  FALSE    TRUE  FALSE FALSE    FALSE           FALSE     FALSE       TRUE
    # [10,]  FALSE    TRUE  FALSE  TRUE    FALSE           FALSE     FALSE      FALSE
    

    结合三部分:

    cbind(lang.df, dd, idx)
    
    #    Nationality             Language.Home lang.home1      lang.home2 lang.home3 Arabic English German Hindi Mandarin Min Nan dialect Norwegian Portuguese
    # 1           HK                  Mandarin   Mandarin            <NA>       <NA>  FALSE   FALSE  FALSE FALSE     TRUE           FALSE     FALSE      FALSE
    # 2       German   Mandarin/English/German   Mandarin         English     German  FALSE    TRUE   TRUE FALSE     TRUE           FALSE     FALSE      FALSE
    # 3        Saudi                    Arabic     Arabic            <NA>       <NA>   TRUE   FALSE  FALSE FALSE    FALSE           FALSE     FALSE      FALSE
    # 4    Norwegian                 Norwegian  Norwegian            <NA>       <NA>  FALSE   FALSE  FALSE FALSE    FALSE           FALSE      TRUE      FALSE
    # 5           UK                   English    English            <NA>       <NA>  FALSE    TRUE  FALSE FALSE    FALSE           FALSE     FALSE      FALSE
    # 6           HK Mandarin/ Min Nan dialect   Mandarin Min Nan dialect       <NA>  FALSE   FALSE  FALSE FALSE     TRUE            TRUE     FALSE      FALSE
    # 7   Australian                  Mandarin   Mandarin            <NA>       <NA>  FALSE   FALSE  FALSE FALSE     TRUE           FALSE     FALSE      FALSE
    # 8           HK                  Mandarin   Mandarin            <NA>       <NA>  FALSE   FALSE  FALSE FALSE     TRUE           FALSE     FALSE      FALSE
    # 9    Brazilian        Portuguese/English Portuguese         English       <NA>  FALSE    TRUE  FALSE FALSE    FALSE           FALSE     FALSE       TRUE
    # 10      Indian             Hindi/English      Hindi         English       <NA>  FALSE    TRUE  FALSE  TRUE    FALSE           FALSE     FALSE      FALSE
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-11
      • 2023-02-09
      • 1970-01-01
      • 1970-01-01
      • 2021-07-25
      相关资源
      最近更新 更多