我的每个数据列都将重新调整并放入0到100的bin中.bin列将用作模型的功能。为了分别测试每个bin,我想将每个bin列拆分为每个bin的值。新列将保持0或1,具体取决于单元格中的值是否与列的bin匹配。从这样的事情:
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
}
}
非常感谢!!
修改
这些都是很好的答案,谢谢大家。最终对象,无论是矩阵,表还是data.table,都只包含单独的bin列(没有源列)。以下解决方案如何用于2000多个源列?
EDIT2
根据我的后续问题的答案,以下是针对将来遇到此问题的任何人的每种方法的实现。
# read in some data with multiple columns
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 's method using a matrix
df_in$row <- NULL
col_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 's method using '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 's method using 'data.table'
# read in data first
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 = 1L
col_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=", "))
所有答案都是适当且可用的,因此最快的答案是最快的答案。再次感谢您的帮助!!
答案 0 :(得分:2)
我经常这样做。这是我用来制作假人的方法。它非常快。
## reading in your example data
df <- read.table(file = "clipboard", header=TRUE)
df$row <- NULL
uniq <- 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
答案 1 :(得分:1)
使用table
:
df1 <- read.table(text="row values
1 10
2 20
3 30
4 40
5 10
6 30
7 40", header=TRUE, stringsAsFactors=FALSE)
table(df1)
values
row 10 20 30 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
您可以像这样对table
编制索引:
table(df1)[5,1]
[1] 1
修改强> 要回答您的其他请求,您可以创建新的列名:
tbl <-table(df1)
out<-as.data.frame.matrix(tbl) #to transform into a data.frame
colnames(out) <-make.names(colnames(out)) #to make new column names
out
X10 X20 X30 X40
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
答案 2 :(得分:1)
这是一个data.table
解决方案。我首先添加count
列,然后使用dcast()
重新整形为宽格式。顺便说一下,这足够快,可用于1000万或更多行的数据。
library(data.table)
tab = fread("row values
1 10
2 20
3 30
4 40
5 10
6 30
7 40")
tab$count = 1L
res = dcast(tab, row ~ values, value.var="count", fill=0L)
res
# row 10 20 30 40
# 1: 1 1 0 0 0
# 2: 2 0 1 0 0
# 3: 3 0 0 1 0
# 4: 4 0 0 0 1
# 5: 5 1 0 0 0
# 6: 6 0 0 1 0
# 7: 7 0 0 0 1