簡體   English   中英

將唯一值拆分為多個列的單獨列

[英]Split unique values into separate columns for multiple columns

我的數據的每個列都將重新縮放並放入0到100的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多個源列?

編輯2

根據對我的后續問題的答案,以下是針對將來遇到此問題的任何人的每種方法的實現。

# 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=", "))

所有答案都是適當且可用的,因此最好的答案是最快的初始響應。 再次感謝你的幫助!!

我經常這樣做。 這是我用來創建假人的方法。 非常快。

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

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

這是一個data.table解決方案。 我首先添加一個count列,然后使用dcast()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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM