【问题标题】:R data.table how to replace positive values with column names across multiple binary data columnsR data.table如何用跨多个二进制数据列的列名替换正值
【发布时间】:2016-01-20 21:26:04
【问题描述】:

我正在使用 R v. 3.2.1 和 data.table v 1.9.6。 我有一个如下例所示的 data.table,其中包含一些编码为字符的二进制列,其值为“0”和“1”,还包含一个字符串向量,其中包含一些与二进制列名称相同的词的短语。我的最终目标是使用字符串向量中的单词和二进制向量中的积极响应来创建一个词云。为此,我首先需要将二进制向量中的肯定响应转换为它们的列名,但是我遇到了困难。

here 提出了类似的问题,但它与海报以矩阵开头并不完全相同,并且建议的解决方案似乎不适用于更复杂的数据集。除了我的二进制列之外,我还有其他列,因此解决方案需要首先准确识别我的二进制列。

以下是一些示例数据:

id <- c(1,2,3,4,5)
age <- c("5", "1", "11", "20", "21")
apple <- c("0", "1", NA, "1", "0")
pear <- c("1", "1", "1", "0", "0")
banana <- c("0", "1", "1", NA, "1")
favfood <- c("i love pear juice", "i eat chinese pears and crab apples every sunday", "i also like apple tart", "i like crab apple juice", "i hate most fruit except bananas" )

df <- as.data.frame(cbind(id, age, apple, pear, banana, favfood), stringsAsFactors=FALSE)
dt <- data.table(df)
dt[, id := as.numeric(id)]

数据如下所示:

    id age apple pear banana                                          favfood
1:  1   5     0    1      0                                i love pear juice
2:  2   1     1    1      1 i eat chinese pears and crab apples every sunday
3:  3  11    NA    1      1                           i also like apple tart
4:  4  20     1    0     NA                          i like crab apple juice
5:  5  21     0    0      1                 i hate most fruit except bananas

因此,如果 apple==1 或 favfood 包含字符串“apple”或两者兼有,则 wordcloud 的苹果频率应该为 1,依此类推。

这是我的尝试(没有达到我想要的效果,但大约完成了一半):

# First define the logic columns.
# I've done this by name here but in my real data set this won't work because there are too many    
logicols <- c("apple", "pear", "banana")

# Next identify the location of the "1"s within the subset of logic columns:
ones <- which(dt==1 & colnames(dt) %in% logicols, arr.ind=T)

# Lastly, convert the "1"s in the subset to their column names:
dt[ones, ]<-colnames(dt)[ones[,2]]

这给出了:

> dt
   id age apple pear banana                                          favfood
1:  1   5     0 pear      0                                i love pear juice
2:  2   1     1 pear banana i eat chinese pears and crab apples every sunday
3:  3  11    NA    1 banana                           i also like apple tart
4:  4  20     1    0     NA                          i like crab apple juice
5:  5  21     0    0      1                 i hate most fruit except bananas

这种方法有两个问题:

(a) 按名称识别要转换的列对于我的真实数据集并不方便,因为它们很多。如何在不包括其他包含 1 但也包含其他值的列的情况下识别此列子集(在此示例中,“年龄”包含 1,但它显然不是逻辑列)?在示例中,我故意将“年龄”编码为字符列,就像在我的真实数据集中一样,有些字符列包含不是逻辑列的 1。使它们与众不同的特点是我的逻辑列是字符,但仅包含值 0、1 或缺失 (NA)。

(b) 索引没有拾取逻辑列中的所有 1,有谁知道这是为什么(例如“apple”列的第二行中的 1 没有转换)?

非常感谢您的帮助 - 我确定我错过了一些相对简单的东西,但我一直坚持这一点。

【问题讨论】:

  • 我认为(尚未阅读完整问题)您应该从melt(dt,id.vars=c("id","age","favfood")) 开始,然后从那里开始。此外,R 有一类特殊的对象,仅用于存储逻辑。见?logical。我建议使用它而不是“0”/“1”/“NA”
  • 这是一个有趣的建议。我可能会遇到问题,因为我仍然需要命名一些变量。我的真实数据集有大约 50 个要转换的逻辑列和 400 个需要插入 id.vars 的列,因此我仍然需要一种区分逻辑和所有其他列类型的方法。另外 - 之前没有真正使用过融化,但有没有办法在之后“解开”(词云将每条记录计为一个文档,最终的 dt 需要采用平面格式)。
  • 啊 - 刚刚看到您评论的第二部分。我已经转换了我的代码以从 STATA 脚本进行初始清理,因此 0 和 1 - 在我刚才检查之前已经忘记了这一点。这当然解决了识别 coiumns 的问题 - 将尝试看看这是否有助于解决第二个问题。
  • 如果您的 400 列中的某些列是由其他列确定的(例如 id 确定 age),那么您可以将它们拆分到自己的表中。 id_attributes = dt[,c("id",other_var_names), with=FALSE] 然后做melt(dt[, !other_var_names, with=FALSE], id.vars="id")。无论如何,这是我的偏好:多张桌子,而不是一张有许多变量的宽桌子。

标签: r replace logic data.table multiple-columns


【解决方案1】:

感谢@Frank 指出应该使用as.logical() 将逻辑/二进制列转换为正确的类。

这大大简化了对要更改的值的识别,并且索引现在似乎也可以工作:

# Starting with the data in its original format:
id <- c(1,2,3,4,5)
age <- c("5", "1", "11", "20", "21")
apple <- c("0", "1", NA, "1", "0")
pear <- c("1", "1", "1", "0", "0")
banana <- c("0", "1", "1", NA, "1")
favfood <- c("i love pear juice", "i eat chinese pears and crab apples every sunday", "i also like apple tart", "i like crab apple juice", "i hate most fruit except bananas" )

df <- as.data.frame(cbind(id, age, apple, pear, banana, favfood), stringsAsFactors=FALSE)

# Convert the "0" / "1" character columns to logical with a function:

    > recode.multi
    function(data, recode.cols, old.var, new.var, format = as.numeric){
      # function to recode multiple columns 
      #
      # Args:        data: a data.frame 
      #       recode.cols: a character vector containing the names of those 
      #                    columns to recode
      #           old.var: a character vector containing values to be recorded
      #           new.var:  a character vector containing desired recoded values
      #            format: a function descrbing the desired format e.g.
      #                    as.character, as.numeric, as.factor, etc.. 

      # check from and to are of equal length
      if(length(old.var) == length(new.var)){
        NULL
      } else {
        stop("'from' and 'to' are of differing lengths")
      }

      # convert format of selected columns to character
      if(length(recode.cols) == 1){
        data[, recode.cols] = as.character(data[, recode.cols])
      } else {
        data[, recode.cols] = data.frame(lapply(data[, recode.cols], as.character), stringsAsFactors=FALSE)
      }


      # recode old variables to new variables for selected columns
      for(i in 1:length(old.var)){
        data[, recode.cols][data[, recode.cols] == old.var[i]] = new.var[i]
      }


  # convert recoded columns to desired format 
  data[, recode.cols] = sapply(data[, recode.cols], format)

  data
}

df = recode.multi(data = df, recode.cols = c(unlist(strsplit("apple pear banana", split=" "))), old.var = c("0", "1", NA), new.var = c(FALSE, TRUE, NA), format = as.logical)

dt <- data.table(df)
dt[, id := as.numeric(id)]

# Identify the values to swap with column names:
convtoname <- which(dt==TRUE, arr.ind=T)

# Make the swap:
dt[convtoname, ]<-colnames(dt)[convtoname[,2]]

这给出了预期的结果:

> dt
   id age apple  pear banana                                          favfood
1: id   5 FALSE  pear  FALSE                                i love pear juice
2:  2   1 apple  pear banana i eat chinese pears and crab apples every sunday
3:  3  11    NA  pear banana                           i also like apple tart
4:  4  20 apple FALSE     NA                          i like crab apple juice
5:  5  21 FALSE FALSE banana                 i hate most fruit except bananas

【讨论】:

    猜你喜欢
    • 2016-08-26
    • 1970-01-01
    • 2017-09-21
    • 1970-01-01
    • 2021-08-21
    • 2021-11-24
    • 2020-01-08
    • 2014-11-04
    • 1970-01-01
    相关资源
    最近更新 更多