转换一个表格 – 用分号分隔的值将列转换为带有是/否条目的多列

我想将我当前的表格转换成可以轻松过滤的表格。

我有一个表,其中第一列是一个唯一的标识符,第二列是用分号分隔的与该条目相关的问题列表。 除此之外,我还有一些精心定义和列出的专栏。 我的表可能看起来像这样:

|ID|Issue|Title| |ABC.001.0001|Green; Blue|Around and up| |ABC.001.0002|Green; Orange|Over and beyond| |ABC.001.0003|Pink; Orange|Inside out| 

每个| 上面代表表格中列的末尾。

我想转换表易于使用和发布易于过滤。 这将是一个好的结果:

 |ID|Green|Blue|Orange|Pink|Title| |ABC.001.0001|Yes|Yes|No|No|Around and up| |ABC.001.0002|Yes|No|Yes|No|Over and beyond| |ABC.001.0003|No|No|Yes|Yes|Inside out| 

我不想写很多代码。 我想find一些库,可以在几个步骤,如R或八度做转换。 否则,也许有一些步骤可以在MS Excel和MS Access中获得相同的结果。

只是作为一个侧面的问题这个转换叫什么? 整洁的数据? 正常化? 改写(munging)?

您可以使用cSplitsplitstackshape以分号( sep=';' )拆分“Issue”列。 指定long的方向,然后使用dcast.data.table其重新dcast.data.table 。 然后根据是否有NA将“蓝色”中的“值”更改为“粉红色”列为“是/否”。 但是,将结果作为逻辑索引TRUE/FALSEYes/No (我们将从!is.na步骤中获得)相比总是更好。

 library(splitstackshape) library(data.table) res <- dcast.data.table(cSplit(df, 'Issue', sep=';', 'long'), ID+Title~Issue, value.var='Issue') nm1 <- names(res)[3:6] res[,(nm1):=lapply(.SD, function(x) c("No", "Yes")[(!is.na(x))+1L]), .SDcols=nm1] res # ID Title Blue Green Orange Pink #1: ABC.001.0001 Around and up Yes Yes No No #2: ABC.001.0002 Over and beyond No Yes Yes No #3: ABC.001.0003 Inside out No No Yes Yes 

或者你可以使用cSplit_e (来自@Ananda Mahto的评论)

  cSplit_e(df, "Issue", sep = "; ", type = "character", fill = 0, drop = TRUE) 

或者使用base R的选项。 在这里,我用strsplit来拆分“Issue”列,然后rbind列表输出来创build“m1”。 创build一个唯一值(“lvls”)的向量。 使用MARGIN作为“1”进行检查,检查“m1”( lvls %in% x )中每行的“ lvls %in% x ”。 通过给它('x)+ 1L')加上“1”将逻辑向量转换为数字,并将其用作“是/否”值的索引。

  df1 <- df[-2] m1 <- do.call(rbind,strsplit(df$Issue, '; ')) lvls <- unique(c(m1)) df1[lvls] <- t(apply(m1, 1, function(x) c('No', 'Yes')[(lvls %in% x)+1L])) df1 # ID Title Green Pink Blue Orange #1 ABC.001.0001 Around and up Yes No Yes No #2 ABC.001.0002 Over and beyond Yes No No Yes #3 ABC.001.0003 Inside out No Yes No Yes 

数据

  df <- structure(list(ID = c("ABC.001.0001", "ABC.001.0002", "ABC.001.0003"), Issue = c("Green; Blue", "Green; Orange", "Pink; Orange"), Title = c("Around and up", "Over and beyond", "Inside out")), .Names = c("ID", "Issue", "Title"), class = "data.frame", row.names = c(NA, -3L))