转换表 - 将具有分号分隔值的列转换为具有是/否条目的多个列

时间:2015-01-27 09:09:58

标签: r excel normalization

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

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

|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|

我不想写很多代码。我想找到一些可以通过几个步骤进行转换的库,例如R或Octave。否则,我可以在MS Excel和MS Access中采取一些步骤来实现相同的结果。

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

1 个答案:

答案 0 :(得分:3)

您可以使用cSplit中的splitstackshape以分号(sep=';')拆分“问题”列。指定long的方向,然后使用wide将其重新整理为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拆分“问题”列,然后rbind列表输出以创建“m1”。创建唯一值的向量(“lvls”)。使用lvls %in% x并使用MARGIN作为“1”检查“m1”(apply)的每一行中的“lvls”中的哪一个。通过向它添加“1”('x)+ 1L`将逻辑向量转换为数字,并将其用作“是/否”值的索引。

 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))