我的数据的每一列将被重新缩放,并划分为从0到100的区间。这些区间列将作为模型的特征。为了单独测试每个区间,我希望将每个区间列拆分为独立的列,每个列对应一个值。新列将包含0或1,具体取决于单元格中的值是否与列的区间匹配。类似这样的数据:
row values 1 10 2 20 3 30 4 40 5 10 6 30 7 40
转换为这样:
row values_10 values_20 values_30 values_40 1 1 0 0 0 2 0 1 0 0 3 0 0 1 0 4 0 0 0 1 5 1 0 0 0 6 0 0 1 0 7 0 0 0 1
这种蛮力方法可以完成任务,但一定有更好的(非循环)方法:
values <- c( 10,20,30,40,10,30,40)dat <- data.frame(values)columnNames <- unique(dat$values)for( n in 1:length(columnNames) ){ dat[as.character(columnNames[n])] <- 0}columnNames2 <- colnames(dat)for( c in 2:ncol(dat)){ hdr <- columnNames2[c] for( r in 1:nrow(dat)) { if( dat$values[r]==as.integer(hdr) ) dat[r,c]=1 }}
非常感谢!!
编辑
这些都是很棒的回答,谢谢大家。最终对象,无论是矩阵、表格还是数据表,只会包含独立的区间列(不包含源列)。如何将下面的解决方案用于2000多个源列?
编辑2
根据我后续问题的答案,下面是为未来参考此问题的人提供的每种方法的实现。
# 读取包含多个列的数据df_in <- read.table(text="row val1 val2 1 10 100 2 20 200 3 30 300 4 40 400 5 10 100 6 30 300 7 40 400", header=TRUE, stringsAsFactors=FALSE)# @Zelazny7 使用矩阵的方法df_in$row <- NULLcol_names <- names(df_in)for( c in 1:length(col_names)){ uniq <- unlist(unique(df_in[col_names[c]])) m <- matrix(0, nrow(df_in), length(uniq), dimnames = list(NULL, paste0(col_names[c], "_", uniq))) for (i in seq_along(df_in[[col_names[c]]])) { k <- match(df_in[[col_names[c]]][i], uniq, 0) m[i,k] <- 1 } if( c==1 ) df_out <- m else df_out <- cbind(df_out,m)}# @P Lapointe 使用'table'的方法col_names <- names(df_in)for( c in 2:length(col_names)){ m <- table(df_in$row,df_in[[col_names[c]]]) uniq <- unlist(unique(df_in[col_names[c]])) newNames <- toString(paste0(col_names[c],'_',uniq)) if( c==2 ){ df_out <- m hdrs <- newNames } else{ df_out <- cbind(df_out,m) hdrs <- paste(hdrs,newNames,sep=", ") }}colnames(df_out) <- unlist(strsplit(hdrs, split=", "))# @bdemarest 使用'data.table'的方法# 首先读取数据library(data.table)df_in = fread("row val1 val2 1 10 100 2 20 200 3 30 300 4 40 400 5 10 100 6 30 300 7 40 400")df_in$count = 1Lcol_names <- names(df_in)for( c in 2:length(col_names)-1){ m = dcast(df_in, paste( 'row', '~', col_names[c]), value.var="count", fill=0L) uniq <- unlist(unique(df_in[,get(col_names[c])])) newNames <- toString(paste0(col_names[c],'_',uniq)) m$row <- NULL if( c==2 ){ df_out <- m hdrs <- newNames } else if( c>2 ){ df_out <- cbind(df_out,m) hdrs <- paste(hdrs,newNames,sep=", ") }}colnames(df_out) <- unlist(strsplit(hdrs, split=", "))
所有答案都适用且可用,因此最佳答案授予最快的初始回应。再次感谢您的帮助!!
回答:
我经常这样做。这是我的创建虚拟变量的方法,速度非常快。
## 读取您的示例数据df <- read.table(file = "clipboard", header=TRUE)df$row <- NULLuniq <- unique(df$values)m <- matrix(0, nrow(df), length(uniq), dimnames = list(NULL, paste0("column_", uniq)))for (i in seq_along(df$values)) { k <- match(df$values[i], uniq, 0) m[i,k] <- 1}
结果如下:
> m column_10 column_20 column_30 column_40[1,] 1 0 0 0[2,] 0 1 0 0[3,] 0 0 1 0[4,] 0 0 0 1[5,] 1 0 0 0[6,] 0 0 1 0[7,] 0 0 0 1
另一种避免循环的方法,通过使用矩阵索引矩阵:
m[cbind(seq.int(nrow(m)), match(df$values, uniq))] <- 1