【问题标题】:Fill in columns with 1 or 0, if that colname matches a variable found in other named columns within the same dataframe如果该列名与同一数据框中其他命名列中的变量匹配,则用 1 或 0 填充列
【发布时间】:2015-09-21 19:03:47
【问题描述】:
view(fastcars)

   day    car1   car2   car3
1 day1   red  silver   blue
2 day2  blue    red   green
3 day3  blue  white   green
4 day4 green  black     red
5 day5 black    red  silver

将所有颜色的汽车合并到一个具有唯一名称的列表中。

cars <- stack(fastcars[, c(2:4)])
cars <- t(unique(cars[,1]))

将颜色作为列名添加到数据框的末尾

fastcars[c(cars)] <- NA

   day  car1   car2   car3  red blue green black silver white
1 day1   red  silver  blue  NA   NA    NA    NA     NA    NA
2 day2  blue    red  green  NA   NA    NA    NA     NA    NA
3 day3  blue  white  green  NA   NA    NA    NA     NA    NA
4 day4 green  black    red  NA   NA    NA    NA     NA    NA
5 day5 black    red silver  NA   NA    NA    NA     NA    NA

如果列名与 car1、car2 和/或 car3 列中的变量匹配,则希望用 1 或 0 填充 NA。

day car1     car2    car3   red  blue green black silver white
day1     red   silver    blue      1    1     0     0      1     0
day2    blue      red   green      1    1     1     0      0     0
day3    blue    white   green      0    1     1     0      0     1
day4   green    black     red      1    0     1     1      0     0
day5   black      red   silver     1    0     0     1      1     0`

我相信这里的这个链接与我想要做的很接近,但无法弄清楚如何在我现有的数据框中创建它。 https://stackoverflow.com/a/30274596/3837899

#Generate example dataframe with character column

example <- as.data.frame(c("A", "A", "B", "F", "C", "G", "C", "D", "E", "F"))
names(example) <- "strcol"

#For every unique value in the string column, create a new 1/0 column
#This is what Factors do "under-the-hood" automatically when passed to    function requiring numeric data

for(level in unique(example$strcol)){
  example[paste("dummy", level, sep = "_")] <- ifelse(example$strcol == level, 1, 0)
}

【问题讨论】:

    标签: r


    【解决方案1】:

    这里有几个选项。

    选项 1:我们可以在重新铸造熔化的数据后使用 data.table 合并。

    library(data.table) # v1.9.6
    ## make 'df' a data.table
    setDT(df)
    ## melt, cast, and merge on 'day'
    df[dcast(melt(df, "day"), day ~ value, fun.aggregate = length), on = "day"]
    #     day  car1   car2   car3 black blue green red silver white
    # 1: day1   red silver   blue     0    1     0   1      1     0
    # 2: day2  blue    red  green     0    1     1   1      0     0
    # 3: day3  blue  white  green     0    1     1   0      0     1
    # 4: day4 green  black    red     1    0     1   1      0     0
    # 5: day5 black    red silver     1    0     0   1      1     0
    

    选项 2:这是一种不太吸引人但合理的基础 R 方法。

    ## make sure car columns are character (may not be necessary)
    df[-1] <- lapply(df[-1], as.character)
    ## get unique values of car columns
    u <- unique(unlist(df[-1]))
    ## match 'u' with each row in 'df'
    l <- lapply(seq_len(nrow(df)), function(i) as.numeric(u %in% df[i, -1]))
    ## bring the data together
    cbind(df, setNames(do.call(rbind.data.frame, l), u))
    #    day  car1   car2   car3 red blue green black silver white
    # 1 day1   red silver   blue   1    1     0     0      1     0
    # 2 day2  blue    red  green   1    1     1     0      0     0
    # 3 day3  blue  white  green   0    1     1     0      0     1
    # 4 day4 green  black    red   1    0     1     1      0     0
    # 5 day5 black    red silver   1    0     0     1      1     0
    

    数据:

    df <-structure(list(day = structure(1:5, .Label = c("day1", "day2", 
    "day3", "day4", "day5"), class = "factor"), car1 = structure(c(4L, 
    2L, 2L, 3L, 1L), .Label = c("black", "blue", "green", "red"), class = "factor"), 
        car2 = structure(c(3L, 2L, 4L, 1L, 2L), .Label = c("black", 
        "red", "silver", "white"), class = "factor"), car3 = structure(c(1L, 
        2L, 2L, 3L, 4L), .Label = c("blue", "green", "red", "silver"
        ), class = "factor")), .Names = c("day", "car1", "car2", 
    "car3"), class = "data.frame", row.names = c("1", "2", "3", "4", 
    "5"))
    

    【讨论】:

      【解决方案2】:

      从此data.frame开始:

      > fastcars
         day  car1   car2   car3 red blue green black silver white
      1 day1   red silver   blue  NA   NA    NA    NA     NA    NA
      2 day2  blue    red  green  NA   NA    NA    NA     NA    NA
      3 day3  blue  white  green  NA   NA    NA    NA     NA    NA
      4 day4 green  black    red  NA   NA    NA    NA     NA    NA
      5 day5 black    red silver  NA   NA    NA    NA     NA    NA
      

      这看起来像是使用 base-R 的一种方法:

      #for every colour fill in each column
      for (i in c('red','blue','green','black','silver','white')){
        #a simple apply per row is returning 1 if any row has the corresponding colour
        #or a 0 otherwise
        fastcars[, i] <- apply(fastcars[2:4], 1, function(x) ifelse(any(x==i),1,0) )
      }
      

      输出:

      > fastcars
         day  car1   car2   car3 red blue green black silver white
      1 day1   red silver   blue   1    1     0     0      1     0
      2 day2  blue    red  green   1    1     1     0      0     0
      3 day3  blue  white  green   0    1     1     0      0     1
      4 day4 green  black    red   1    0     1     1      0     0
      5 day5 black    red silver   1    0     0     1      1     0
      

      【讨论】:

      • 这么多答案这么快!我首先尝试了这个,它适用于我更大的 DF。谢谢
      • 不客气 :)。公平地说,如果您有一个大的 data.frame(100K+ 行)并且您对速度感兴趣 @jeremycg 的答案可能是最快的。对于较小的数据集,这是可以的,因为它依赖于 base-R 并且易于理解。
      【解决方案3】:

      使用dplyrtidyr

      library(dplyr)
      library(tidyr)
      fastcars %>% gather(car, col, -day) %>%
                   spread(col, car) %>%
                   mutate_each(funs(+!is.na(.)), -day) %>%
                   left_join(fastcars, ., by = "day")
      
         day  car1   car2   car3 black blue green red silver white
      1 day1   red silver   blue     0    1     0   1      1     0
      2 day2  blue    red  green     0    1     1   1      0     0
      3 day3  blue  white  green     0    1     1   0      0     1
      4 day4 green  black    red     1    0     1   1      0     0
      5 day5 black    red silver     1    0     0   1      1     0
      

      【讨论】:

        【解决方案4】:

        已经有很多很棒的答案了。这个有点神秘,但在基础 R 中。

        fastcars <- data.frame(day=paste0("day", 1:5), 
          car1 = c("red", "blue", "blue", "green", "black"), 
          car2 = c("silver", "red", "white", "black", "red"), 
          car3 = c("blue", "green", "green", "red", "silver"), stringsAsFactors=FALSE)
        
        # for aggregate function
        msum <- function(x) min(sum(x), 1)
        
        cars <- data.frame(day=rep(paste0("day", 1:nrow(fastcars)), 3), stack(fastcars, select=-day))
        cars <- cbind(cars, model.matrix(ind ~ values - 1, data=cars))
        res <- aggregate(cars[, -c(1:3)], list(cars$day), msum)
        merge(fastcars, res, by.x="day", by.y="Group.1") 
        
           day  car1   car2   car3 valuesblack valuesblue valuesgreen valuesred valuessilver valueswhite
        1 day1   red silver   blue           0          1           0         1            1           0
        2 day2  blue    red  green           0          1           1         1            0           0
        3 day3  blue  white  green           0          1           1         0            0           1
        4 day4 green  black    red           1          0           1         1            0           0
        5 day5 black    red silver           1          0           0         1            1           0
        

        【讨论】:

          【解决方案5】:

          请给我们dput

          使用reshape2

          感谢 Richard Scriven,我正在处理他的数据结构

              dd2<-melt(df,id.vars="day")
              dd3<-dcast(data=dd2, day ~ value, value.var="value", length)
              merge(df, dd3, by="day")
             day  car1   car2   car3 black blue green red silver white
          1 day1   red silver   blue     0    1     0   1      1     0
          2 day2  blue    red  green     0    1     1   1      0     0
          3 day3  blue  white  green     0    1     1   0      0     1
          4 day4 green  black    red     1    0     1   1      0     0
          5 day5 black    red silver     1    0     0   1      1     0
          

          【讨论】:

            【解决方案6】:

            我们也可以使用table 来做到这一点。我们unlist 'car' 列,cbind 与第一列,得到table,将其转换为data.framecbind 与原始数据集。

            cbind(fastcars,as.data.frame.matrix(table(cbind(fastcars[1],
                         cars=unlist(fastcars[2:4])))))
            #     day  car1   car2   car3 black blue green red silver white
            #1 day1   red silver   blue     0    1     0   1      1     0
            #2 day2  blue    red  green     0    1     1   1      0     0
            #3 day3  blue  white  green     0    1     1   0      0     1
            #4 day4 green  black    red     1    0     1   1      0     0
            #5 day5 black    red silver     1    0     0   1      1     0
            

            【讨论】:

              【解决方案7】:

              我把这个打了个码:

              fastcars <- cbind(fastcars, 
                do.call(pmax, lapply(fastcars[-1], outer, setNames(nm=unique(unlist(fastcars[-1]))), `==`))
              )
              

              对于car1, car2, car3 中的每一个,使用outer 制作一个虚拟矩阵,然后将do.call(pmax) 放在一起。

              【讨论】:

                猜你喜欢
                • 2020-09-13
                • 1970-01-01
                • 2019-11-20
                • 2020-04-29
                • 1970-01-01
                • 2016-09-13
                • 2021-05-06
                • 2016-12-11
                • 2020-11-26
                相关资源
                最近更新 更多