R:使数据框中所有因子列中的重复级别唯一

时间:2014-11-29 12:39:41

标签: r dataframe duplicates factors levels

已经好几天了,我已经遇到了R中的问题,尝试使用循环在数据帧中的多个因子列中创建重复级别。这是一个更大项目的一部分。

我有超过200个SPSS数据集,其中案例数在4,000到23,000之间变化,变量数在120到1,200之间变化(其中一个SPSS数据集的摘录{ {3}})。这些文件包含数字和因子变量,许多因子都有重复的级别。我已经使用外部包中的read.spss将它们导入到数据框中,保留了值标签,因为我需要它们以供进一步使用。在导入期间,R警告我有关因子列中的重复级别:

> adn <- read.spss("/tmp/adn_110.sav", use.value.labels = TRUE,
use.missings = TRUE, to.data.frame = TRUE)
Warning messages:
1: In read.spss("/tmp/adn_110.sav", use.value.labels = TRUE, use.missings = TRUE,  :
  /tmp/adn_110.sav: Unrecognized record type 7, subtype 18 encountered in system file
2: In `levels<-`(`*tmp*`, value = if (nl == nL) as.character(labels) else paste0(labels,  :
  duplicated levels in factors are deprecated
3: In `levels<-`(`*tmp*`, value = if (nl == nL) as.character(labels) else paste0(labels,  :
  duplicated levels in factors are deprecated

数据框,导出为.RDatacan be found here。当我使用table(例如)获取任何因子列的每个级别的计数时,将显示所有重复级别,但所有重复级别的计数将添加到重复级别的第一次出现并且对于所有级别返回其他0:

> table(adn[["adn01"]], useNA = "ifany")
  Incorrect         Incorrect Partially correct Partially correct 
          8                 0                 4                 0 
    Correct              <NA> 
          2                 1 
Warning message:
In `levels<-`(`*tmp*`, value = if (nl == nL) as.character(labels) else paste0(labels,  :
  duplicated levels in factors are deprecated

我知道在调用as.numeric时我可以轻松地处理因子table。但是,我需要输出中显示的级别名称。我可以使用make.unique使各个因子列的级别唯一,在重复级别的末尾附加一个数字:

> levels(adn[["adn01"]]) <- make.unique(levels(adn[["adn01"]]), sep = " ")

像魅力一样工作。然后table向我展示了正确的计数:

> table(adn[["adn01"]], useNA = "ifany")

          Incorrect         Incorrect 1   Partially correct 
                  5                   3                   1 
Partially correct 1             Correct                <NA> 
                  3                   2                   1 

但是,对于200多个文件中的每一个中的每个因子列执行此操作,其中变量的数量在120和1,200之间变化,这将是一生的任务。如果文件发生变化,我将不得不重做所有内容。我天真地认为循环通过ccolums会很容易。但是,make.table需要名称。我尝试过以下方法:

> lapply(adn[ , 1:length(adn)], make.unique(as.vector(attr(adn[ , 1:length(adn)],
"levels"))))
Error in make.unique(as.vector(attr(adn[, 1:length(adn)], "levels"))) : 
  'names' must be a character vector

没有运气。我在最后几天尝试了很多其他的东西,包括经典的for循环。仍然相同:'names' must be a character vector。我想问题是索引列的属性levels,这是一个列表组件,但我无法弄清楚是什么。其他问题可能是并非所有列都是因素。有人可以帮忙吗?

修改

can be found here提供的解决方案完美无缺。再次感谢你!

1 个答案:

答案 0 :(得分:1)

尝试

 load('adn.RData')
 indx <- sapply(adn, is.factor)
 adn[indx] <- lapply(adn[indx], function(x) {
                   levels(x) <- make.unique(levels(x))
                   x })


 table(adn[['adn01']], useNA='ifany')

 #     Incorrect         Incorrect.1   Partially correct Partially correct.1 
 #             5                   3                   1                   3 
 #       Correct                <NA> 
 #             2                   1 


  table(adn[['adn03']], useNA='ifany')

  #  Incorrect Partially correct           Correct              <NA> 
  #          6                 3                 5                 1 

更新

如果您有多个文件,可以将文件读入列表,然后在list上进行处理。例如,考虑到文件位于工作目录中。

files <- list.files(pattern='^adn\\d+')
lst1 <- lapply(files, function(x) read.spss(x, use.value.labels = TRUE,
          use.missings = TRUE, to.data.frame = TRUE) #not tested

出于测试目的,我使用相同的数据集lst1创建adn

adn1 <- adn
lst1 <- list(adn, adn1)

现在,您为每个make.unique元素应用list

lst2 <- lapply(lst1, function(dat) {
                  indx <- sapply(dat, is.factor)
                  dat[indx] <- lapply(dat[indx], function(x){
                           levels(x) <- make.unique(levels(x))
                            x})
                          dat})


  lapply(lst2, function(x) table(x[['adn01']], useNA='ifany'))
  # [[1]]

  #    Incorrect         Incorrect.1   Partially correct Partially correct.1 
  #            5                   3                   1                   3 
  #      Correct                <NA> 
  #            2                   1 

  # [[2]]

  #    Incorrect         Incorrect.1   Partially correct Partially correct.1 
  #            5                   3                   1                   3 
  #      Correct                <NA> 
  #            2                   1