在数据框中分隔一列,其中每个观察值可以有多个并发值
Separate a column in dataframe where each observation can have multiple concurrent values
我相信我的问题既是关于最佳实践的问题,也是关于整理杂乱数据的问题,所以这里开始吧。
以下是数据框 lang.df
的摘录,这是一个全校学生数据集。 Langauge.Home
列表示家长对问题的回答:
"What languages do you speak at 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)
}
问题
- 这种情况叫什么?我试图查看
tidyr
文档和此处的 SO,但找不到任何相关信息。
- 有没有比我所做的更优雅的转换编码方式?
- 什么是最佳实践
- 获取此数据(以更改未来的数据输入过程)
- 从统计角度处理这种情况
在此先感谢您的帮助。我断断续续地使用 R 大约一年了,这是我的第一个 SO post。尽可能多地给我反馈!
数据
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")
我们可以使用 splitstackshape
中的 cSplit
使用分隔符 /
拆分 'Language.Home' 并将其转换为 long
格式。
library(splitstackshape)
library(data.table)
dt <- cSplit(lang.df, "Language.Home", "/", "long")
然后,使用dcast
将'long'转换为'wide'
dcast(dt, Nationality~Language.Home, fun.aggregate = function(x) length(x)>0)
注意:有重复的 'Nationality' 行,因此上面将把共同的元素组合在一起。把它组合在一起可能会更好。
如果我们需要有基于每一行的逻辑列(不考虑相似'Nationality')
dcast(cSplit(setDT(lang.df, keep.rownames=TRUE), "Language.Home",
"/", "long"), rn +Nationality ~Language.Home, function(x) length(x) >0)
或者另一个选项是 qdapTools
中的 mtabulate
在将 '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
获得长格式的一种简单方法是使用 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
这是一个基本方法,总共只有几行
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
我相信我的问题既是关于最佳实践的问题,也是关于整理杂乱数据的问题,所以这里开始吧。
以下是数据框 lang.df
的摘录,这是一个全校学生数据集。 Langauge.Home
列表示家长对问题的回答:
"What languages do you speak at 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)
}
问题
- 这种情况叫什么?我试图查看
tidyr
文档和此处的 SO,但找不到任何相关信息。 - 有没有比我所做的更优雅的转换编码方式?
- 什么是最佳实践
- 获取此数据(以更改未来的数据输入过程)
- 从统计角度处理这种情况
在此先感谢您的帮助。我断断续续地使用 R 大约一年了,这是我的第一个 SO post。尽可能多地给我反馈!
数据
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")
我们可以使用 splitstackshape
中的 cSplit
使用分隔符 /
拆分 'Language.Home' 并将其转换为 long
格式。
library(splitstackshape)
library(data.table)
dt <- cSplit(lang.df, "Language.Home", "/", "long")
然后,使用dcast
将'long'转换为'wide'
dcast(dt, Nationality~Language.Home, fun.aggregate = function(x) length(x)>0)
注意:有重复的 'Nationality' 行,因此上面将把共同的元素组合在一起。把它组合在一起可能会更好。
如果我们需要有基于每一行的逻辑列(不考虑相似'Nationality')
dcast(cSplit(setDT(lang.df, keep.rownames=TRUE), "Language.Home",
"/", "long"), rn +Nationality ~Language.Home, function(x) length(x) >0)
或者另一个选项是 qdapTools
中的 mtabulate
在将 '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
获得长格式的一种简单方法是使用 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
这是一个基本方法,总共只有几行
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