几天来,我一直困扰于R中的问题,试图使用循环使数据帧中多个因子列中的重复级别唯一。这是一个较大项目的一部分。
我有200多个SPSS
数据集,其中案例数在4,000到23,000之间变化,变量数在120到1200之间变化(可以在这里找到其中一个SPSS
数据集的摘录)。这些文件包含数字变量和因子变量,并且许多因子变量具有重复的级别。我已经使用了外部包中的数据包来导入它们,并保留了值标签,因为我需要它们作进一步的使用。在导入期间,R警告我有关因子列中重复的水平:read.spss
> 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
数据帧,导出为.RData
,可以在这里找到。当我使用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到1200之间变化)将是一生的任务。如果文件更改,我将必须重做所有操作。我天真地认为,遍历各个小室很容易。但是,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
列的属性(这是一个列表组件)上,但是我不知道是什么。另一个问题可能是并非所有列都是因素。有人可以帮忙吗?
编辑:
akrun提供的解决方案效果很好。再一次感谢你!
尝试
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
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句