设置列类和分配因子级别,而不使用循环

时间:2016-02-09 12:22:25

标签: r loops vectorization

我一直在努力解决以下问题,因为我需要尽快加载,操作并从新数据集中生成分数。我已经定义了一个数据字典,其中包含每个变量类的描述(例如数字,因子,字符,日期),以及适用的所有可能因子级别的列表:

DD <- data.frame(Var = c("a", "b", "c", "d"),
   Class = c("Numeric", "Factor", "Factor", "Date"),
   Levels = c(NA, "B1, B2, B3", "C1, C2", NA))

Data <- data.frame(a = 5, b = "B1", c = "C2", d = "2015-05-01")

最终,我打算使用model.matrix来生成一个设计矩阵,其中包含一组通用的指标变量/列,而不管在特定数据集中观察到的实际因子水平,因此我可以准确地从模型中获取数据。

我需要尽快完成这些任务,因此,我试图找到一种避免使用lapply / loops的解决方案。这是(一个稍微复杂的版本)我现有的设置因子水平的解决方案,目前对我的要求来说太慢了:

lapply(1:ncol(Data[,DD$Class=="Factor"]), function(i) {
   factor( as.character( unlist( Data[,DD$Class=="Factor"][i])) , 
   levels = unlist(strsplit(as.character(DD$Levels[DD$Class=="Factor"][i]), ", ")) )
}) 

任何有关避免在此处使用循环的建议,如果可能的话,或任何其他解决方案将非常感谢!

谢谢!

3 个答案:

答案 0 :(得分:1)

  • 第一句话

将级别存储为需要解析的单个字符串是低效的。我建议使用一个列表并将这些级别直接存储为字符向量。

DD <- list(a = list(class="numeric"),
           b = list(class="factor", levels = c("B1", "B2", "B3")),
           c = list(class="factor", levels = c("C1", "C2")),
           b = list(class="Date"))
  • 第二句话:

您不需要“解构”您的因素来添加新级别。

示例:

fac <- factor(c("a", "b", "a"))
# two levels

factor(fac, letters)
# 26 levels, data has not changed
  • 第三句话

我不知道如何在这里避免“循环”,但是lapply是执行循环的有效方式,我怀疑这是性能瓶颈。使用备注1和2,您可以编写更高效的内部函数。抛弃data.frame以获取data.table或tbl也可能有用。

答案 1 :(得分:0)

您可以在创建数据框时定义列类(以及因子的级别):

mylevels <- c("b1","b2","b3","c1","c2") 

myData <- data.frame(a =
numeric(), b = factor(levels=mylevels), c = factor(levels=mylevels), d
= character())

这将创建一个空白数据框,您可以稍后填写。

回复您的评论:只有当 myData 数据具有相同的列类时,rbind才有效。否则列类将更改。我的观点是:如果您加载的数据相似(具有相同的列数,列具有相同的名称等),那么您可以在加载数据时正确设置类,如:

myclasses <- c(“numeric”,”factor”,”factor”,”date”)
myData <- read.table(“mydatafile.csv”, sep=”,”, header = TRUE, colClasses = myclasses)
myLevels <- c(“a1”,”a2”,”b1”,”b2”)
myfactorlist <- c(“b”,”c”)
levels(myData[,myfactorlist]) <- myLevels

这里我假设您的列名称与前面的示例相同:“a”,“b”,“c”,“d”,其中&#34; c&#34;和&#34; b&#34;是因子列。

答案 2 :(得分:0)

你将对列进行迭代,但可以像这样以更清洁的方式完成。我们假设您要保留输入数据框,因此我们创建一个新的数据框Data2来保存结果。请注意,我们已将DD字符的列设置为而不是因子。 Data来自问题。

DD <- data.frame(Var = c("a", "b", "c", "d"),
   Class = c("Numeric", "Factor", "Factor", "Date"),
   Levels = c(NA, "B1, B2, B3", "C1, C2", NA), stringsAsFactors = FALSE)

Data2 <- Data

# factors
Factors <- subset(DD, Class == "Factor")
Levels <- strsplit(as.character(Factors$Levels), ", ")
Data2[Factors$Var] <- Map(factor, Data2[Factors$Var], Levels)

# dates
Dates <- subset(DD, Class == "Date")
Data2[Dates$Var] <- Map(as.Date, Data2[Dates$Var]) 

,并提供:

> str(Data2)
'data.frame':   1 obs. of  4 variables:
 $ a: num 5
 $ b: Factor w/ 3 levels "B1","B2","B3": 1
 $ c: Factor w/ 2 levels "C1","C2": 2
 $ d: Date, format: "2015-05-01"