【问题标题】:Transform dataframe of characters into a "more clear" dataframe with binary variables in R将字符数据帧转换为 R 中具有二进制变量的“更清晰”的数据帧
【发布时间】:2021-03-28 13:28:31
【问题描述】:

从 R 中的数据框开始,如下所示 (df):

year_1 <- c('James','Mike','Jane', NA)
year_2 <- c('Evelyn', 'Jackson', 'James', 'Avery')
year_3 <- c('Harper', 'Avery', NA, NA)
df <- data.frame(year_1, year_2, year_3)

...我想把它转换成类似 df1 的东西(当然我的原始数据框中有数百个元素,所以我不能手动去)

names <- c('James','Mike','Jane','Evelyn', 'Jackson', 'Avery', 'Harper')
year_1 <- c('YES','YES','YES', 'NO', 'NO', 'NO', 'NO')
year_2 <- c('YES','NO','NO', 'YES', 'YES', 'YES', 'NO')
year_3 <- c('NO','NO','NO', 'NO', 'NO', 'YES', 'YES')
df_1 <- data.frame(year_1, year_2, year_3)
rownames(df_1) <- names

我已经尝试过:

  1. 将 df 的所有元素转换为具有唯一元素的字符串向量
  2. 使用步骤 1) 的名称构造 df1 的结构
  3. 尝试用循环填充 df1(在这里我无法构建一个合适的循环来实现这一点)

有什么想法吗?

谢谢!!

【问题讨论】:

  • 你可以做类似as.data.frame.matrix(table(stack(df)))的事情。
  • “stack.data.frame(df) 中的错误:未选择向量列”
  • 确保您的列是字符,而不是因子。

标签: r dataframe loops foreach binary


【解决方案1】:

这是tidyverse 的一个选项,我们将数据重新整形为“长”格式pivot_longer,获取distinct 行,创建一个“YES”列并使用pivot_wider 重新整形为“宽”

library(dplyr)
library(tidyr)
library(tibble)
df %>%
  pivot_longer(cols = everything(), values_drop_na = TRUE) %>%
  distinct %>%
  mutate(new = 'YES') %>% 
  pivot_wider(names_from = name, values_from = new, values_fill = 'NO') %>%
  column_to_rownames("value")

-输出

#          year_1 year_2 year_3
#James      YES    YES     NO
#Evelyn      NO    YES     NO
#Harper      NO     NO    YES
#Mike       YES     NO     NO
#Jackson     NO    YES     NO
#Avery       NO    YES    YES
#Jane       YES     NO     NO

【讨论】:

  • 超级答案。非常快速和干净!!非常感谢
【解决方案2】:

这个怎么样?

sapply(df, function(x) sapply(na.omit(unique(unlist(df))), `%in%`, x))
#         year_1 year_2 year_3
# James     TRUE   TRUE  FALSE
# Mike      TRUE  FALSE  FALSE
# Jane      TRUE  FALSE  FALSE
# Evelyn   FALSE   TRUE  FALSE
# Jackson  FALSE   TRUE  FALSE
# Avery    FALSE   TRUE   TRUE
# Harper   FALSE  FALSE   TRUE

【讨论】:

    【解决方案3】:

    使用stack + table 的基本 R 选项

    > as.data.frame(ifelse(table(stack(df)) == 1, "YES", "NO"))
            year_1 year_2 year_3
    Avery       NO    YES    YES
    Evelyn      NO    YES     NO
    Harper      NO     NO    YES
    Jackson     NO    YES     NO
    James      YES    YES     NO
    Jane       YES     NO     NO
    Mike       YES     NO     NO
    

    【讨论】:

    • +1 但我可能会使用lapply(df, as.character) 给出他们在问题下的评论,并使用[] 替换而不是ifelse。比如:x &lt;- table(stack(lapply(df, as.character))) + 1; x[] &lt;- c("NO", "YES")[x]; x.
    • @A5C1D2H2I1M1N2O1R2T1 是的,这是有道理的,如果可能我们可以使用type.convert(df,as.is = TRUE)
    【解决方案4】:

    为了提供另一种选择,首先我们可以使用嵌套的 for 循环从 df 中提取唯一名称。我们测试该名称是否已经在我们的列表中,并进一步测试我们是否正在查看 NA。

    people<-c()
    for (i in 1:length(colnames(df))){
      for (j in 1:length(df[,1])){
        pers<-df[j,i]
        if (!(pers %in% people)){
          if (!is.na(pers)){
            people<-c(people,toString(pers))
          }
        }
      }
    }
    

    从这里开始,我们可以对每年进行一次简单的 %in% 检查,并将其组合成一个完整的数据框。上面的答案可能更直接,但我发现如果您需要在数据通过脚本时对数据进行其他小的更改,这样的代码很有用。

    for (i in 1:length(colnames(df))){
      colname<-colnames(df)[i]
      peoplein<-people %in% df[,i]
      if (i == 1){
        df1<-cbind(people,peoplein)
        colnames(df1)[i+1]<-colname
      } else {
        df1<-cbind(df1,peoplein)
        colnames(df1)[i+1]<-colname
      }
    }
    

    生成的 df1 如下所示。

         people    year_1  year_2  year_3 
    [1,] "James"   "TRUE"  "TRUE"  "FALSE"
    [2,] "Mike"    "TRUE"  "FALSE" "FALSE"
    [3,] "Jane"    "TRUE"  "FALSE" "FALSE"
    [4,] "Evelyn"  "FALSE" "TRUE"  "FALSE"
    [5,] "Jackson" "FALSE" "TRUE"  "FALSE"
    [6,] "Avery"   "FALSE" "TRUE"  "TRUE" 
    [7,] "Harper"  "FALSE" "FALSE" "TRUE" 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-22
      • 2023-01-21
      • 1970-01-01
      • 2023-01-18
      • 1970-01-01
      • 1970-01-01
      • 2019-03-11
      相关资源
      最近更新 更多