在R中通过将一个变量拆分成多个变量来创建新列

7

我希望通过在数据框中拆分向量来创建新列。

我有这样一个数据框:

YEAR Variable1 Variable2 
2009 000000    00000001
2010 000000    00000001
2011 000000    00000001
2009 000000    00000002
2010 000000    00000002
2009 000000    00000003
...
2009 100000    10000001
2010 100000    10000001
...
2009 100000    10000011
....

正如您所看到的,Variable2与Variable1有关(Variable2 = Variable1 + 最后两位数字:例如01、02、03...表示子类别)。我想将Variable2分割成与子类别一样多的变量。结果应该是:

YEAR Variable1 Variable2 Variable3 Variable4 ... 
2009 000000    00000001  0         0        
2010 000000    00000001  0         0
2011 000000    00000001  0         0
2009 000000    0         00000002  0
2010 000000    0         00000002  0
2009 000000    0         0         00000003
...
2009 100000    10000001  0         0     
2010 100000    10000001  0         0     
...
2009 100000    0         0         0       ...      10000011 

你会怎么做?我认为我应该尝试在循环中重新编写Variable2。我曾经尝试通过操作字符串来解决问题,但是没有成功。


因此,根据最后两个变量的值,您想创建列并赋值,因此总共将有大约101列,这是您想要的吗? - The6thSense
1
例如,对于 Variable1 中的第一个元素(000000),对应 Variable2 中的 3 个元素(00000001、00000002、00000003),它们应该被重写到三个不同的列中。每当 Variable2 中的一个元素的最后两位是 01 时,该元素仍保留在 Variable2 的列中。当 Variable2 中的一个元素的最后两位为 02 时,该元素会进入 Variable3(或者如果 Variable3 不存在,则创建 Variable3)。这样,只有在必要时才会创建新变量。 - woodstock
6个回答

4
这将奏效。首先让我们构建数据。
values <- paste0("0000000", 1:4)
library(data.table)
dt <- data.table(val = sample(values, 10, replace = TRUE))

一个for循环足以定义新列。
for(level_var in dt[, unique(val)]){
  dt[, eval(level_var) := ifelse(val == level_var, level_var, 0)]
}

2
很好的回答,除了你需要使用 substr(eval(level_var), nchar(eval(level_var)) - 1, nchar(eval(level_var))) := ifelse(val == level_var, level_var, 0),因为似乎 OP 希望 val = xxxxxxyy 对于 yy 的所有可能前缀都是相同的新列。 - Synergist
还有一点工作需要完成,OP希望输出的格式为variabl1,variable2,.....variable99。 - The6thSense
我理解你的意思。"level_var"是什么?我查找了关于" data.table"包的文档,但没有找到有关它的任何信息。谢谢你的帮助!这段代码在我的数据上还不能运行..但我正在努力解决。 - woodstock
1
for (x in y) 创建一个临时变量 x,用于迭代 y 中的值。因此,在这种情况下,level_var 将迭代 dt[, unique(val)] 的值,该值对应于表中 Variable2 列中的唯一值。 - Synergist
啊,好的!明白了!问题有点儿蠢! - woodstock
使用以下代码,可以实现相同的功能,但是使用数据框,并创建所需的“Variable3..VariableN”列命名方案:for (v in 1:length(unique(dt$Variable2))){ dt[,paste('Variable', v+2, sep='')] = ifelse(dt$Variable2==unique(dt$Variable2)[v], unique(dt$Variable2)[v], 0) } - Nicholas McCarthy

1
使用reshape2库。一行代码解决问题。如果需要去除NA值,则再加一行代码。
library(reshape2)
df <- data.frame(YEAR=c(2009,2010,2011,2009,2010,2009,2009,2010,2009),
                 Var1=c('000000','000000','000000','000000','000000','000000','100000','100000','100000'),
                 Var2=c('0000001','0000001','0000001','0000002','0000002','0000003','1000001','1000001','1000011')) 
df <- dcast(df, YEAR + Var1 + Var2 ~ Var2, value.var = "Var2")[, -3]
df[is.na(df)] <- 0

结果:

  YEAR   Var1 0000001 0000002 0000003 1000001 1000011
1 2009 000000 0000001       0       0       0       0
2 2009 000000       0 0000002       0       0       0
3 2009 000000       0       0 0000003       0       0
4 2009 100000       0       0       0 1000001       0
5 2009 100000       0       0       0       0 1000011
6 2010 000000 0000001       0       0       0       0
7 2010 000000       0 0000002       0       0       0
8 2010 100000       0       0       0 1000001       0
9 2011 000000 0000001       0       0       0       0

1

这里有另一个建议。代码有点长,但我相信它可以完成任务,并且希望它易于理解。我假设原始数据存储在名为"data.dat"的制表符分隔文件中。 代码的输出存储在矩阵"new_matrix"中。条目是字符,但如果需要,将它们转换为整数不应该是问题。

data <- read.table('data.dat', sep='\t', header = TRUE, colClasses = "character")
var2 <- data[3]
nc <- nchar(var2[1,1])
last2 <-substr(var2[,1],nc-1,nc)
subcat <-levels(factor(last2))
mrows <- nrow(data)
mcols <- length(subcat)
varnames <-paste0("Variable",as.character(c(1:(mcols+1))))
new_matrix <- matrix(paste(replicate(nc,"0"),collapse=""),nrow=mrows,ncol=mcols+2)
colnames(new_matrix) <- c("YEAR",varnames)
new_matrix[,1]<-data[,1]
new_matrix[,2]<-data[,2]
for (i in 1:mcols) {
    relevant_rows <- which(last2 == subcat[i])
    new_matrix[relevant_rows,i+2]<-data[relevant_rows,3]
}

希望这有所帮助。

0

感谢您提供的所有答案。我通过结合Michele Usuelli的回答和Synergist对他回答的评论找到了解决方案。我也学到了更多关于data.table的知识。

NbTabelle <- data.table(val=Netz)
attach(NbTabelle)
for(level_var in namesvec){
NbTabelle[, eval(level_var) := ifelse(substr(eval(val), 7, 8) == level_var, val, 0)]
}

其中namesvec是我从之前生成的表格中创建的变量名称向量,除了变量val。 我很欣赏Synergist代码的通用性,但是对于我的目的,我只需要最后两位数字。


0
这里有另一种方法。请注意,我选择将子类别虚拟变量转换为二进制指示变量以减少冗余:
输入:
data <- read.table(header=TRUE, text='
  year var1      var2
  2009 000000    00000001
  2010 000000    00000001
  2009 000000    00000002
  2010 000000    00000002
  2009 000000    00000003
  2009 100000    10000001
  2009 100000    10000004
  2010 100000    10000010                 
', colClasses = c('character', 'character', 'character'))

简化 var2 列:

subCat <- function(s) {
  substr(s, nchar(s) - 1, nchar(s))
}
data$var2 <- subCat(data$var2)

创建虚拟变量:

方法1:

t <- table(1:length(data$var2), data$var2)
data <- cbind(data, as.data.frame.matrix(t))
data$var2 <- NULL

输出:

 year   var1 01 02 03 04 10
1 2009 000000  1  0  0  0  0
2 2010 000000  1  0  0  0  0
3 2009 000000  0  1  0  0  0
4 2010 000000  0  1  0  0  0
5 2009 000000  0  0  1  0  0
6 2009 100000  1  0  0  0  0
7 2009 100000  0  0  0  1  0
8 2010 100000  0  0  0  0  1

===========================================================

方法二:

library(dummies)
data$var2 <- subCat(data$var2)
data3 <- cbind(data, dummy(data$var2))
data3$var2 = NULL

输出:

  year   var1 data01 data02 data03 data04 data10
1 2009 000000      1      0      0      0      0
2 2010 000000      1      0      0      0      0
3 2009 000000      0      1      0      0      0
4 2010 000000      0      1      0      0      0
5 2009 000000      0      0      1      0      0
6 2009 100000      1      0      0      0      0
7 2009 100000      0      0      0      1      0
8 2010 100000      0      0      0      0      1

===========================================================

方法三:

dummies <- sapply(unique(data$var2), function(x) as.numeric(data$var2 == x))
data <- cbind(data, dummies)
data$var2 = NULL

输出:

  year   var1 X01 X02 X03 X04 X10
1 2009 000000   1   0   0   0   0
2 2010 000000   1   0   0   0   0
3 2009 000000   0   1   0   0   0
4 2010 000000   0   1   0   0   0
5 2009 000000   0   0   1   0   0
6 2009 100000   1   0   0   0   0
7 2009 100000   0   0   0   1   0
8 2010 100000   0   0   0   0   1

0
library(dplyr)
library(reshape2)
df <- data.frame(YEAR=c(2009,2010,2011,2009,2010,2009,2009,2010,2009),
                         Var1=c('000000','000000','000000','000000','000000','000000','100000','100000','100000'),
                         Var2=c('0000001','0000001','0000001','0000002','0000002','0000003','1000001','1000001','1000011'))

df <- mutate(df, tag=paste(YEAR, Var1, Var2, sep='-'))
df <- dcast(df, YEAR + Var1 + tag ~ Var2, fun.aggregate = NULL)
df$tag <- NULL
df <- apply(df, 2, function(x) sub('^(.*)-(.*)-', '', x))
df[is.na(df)] <- 0
df <- as.data.frame(df)

输出:

  YEAR   Var1 0000001 0000002 0000003 1000001 1000011
1 2009 000000 0000001       0       0       0       0
2 2009 000000       0 0000002       0       0       0
3 2009 000000       0       0 0000003       0       0
4 2009 100000       0       0       0 1000001       0
5 2009 100000       0       0       0       0 1000011
6 2010 000000 0000001       0       0       0       0
7 2010 000000       0 0000002       0       0       0
8 2010 100000       0       0       0 1000001       0
9 2011 000000 0000001       0       0       0       0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接