【问题标题】:R: How to write it in more efficient, more compact, way the code that repeats using the same kind of variablesR:如何以更高效、更紧凑的方式编写使用相同类型的变量重复的代码
【发布时间】:2013-11-24 18:43:22
【问题描述】:

我有一个data.frameDAT,其中有 8 列包含以下格式的字符串(这些是测验的八个问题的多项选择答案):

  Q1  Q2  Q3  Q4  Q5  Q6  Q7  Q8
1 ,,1 ,,1 ,1, 1,, ,,1 ,,1 ,1, 1,,
2 ,,1 ,,1 ,1, 1,, ,,1 ,,1 ,1, 1,,
3 ,,1 ,,1 ,1, 1,, ,,1 ,,1 ,1, 1,,
4 ,,1 ,,1 ,1, 1,, ,,1 ,,1 ,1, 1,,
5 ,,1 ,,1 ,1, 1,, ,,1 ,,1 ,1, 1,,
6 ,,1 ,,1 ,1, 1,, ,,1 ,,1 ,1, 1,,

我想将其转换为以下内容:

 q11 q12 q13 q21 q22 q23 q31 q32 q33 q41 q42 q43 q51 q52 q53 q61 q62 q63 q71 q72 q73 q81 q82 q83
1   0   0   1   0   0   1   0   1   0   1   0   0   0   0   1   0   0   1   0   1   0   1   0   0
2   0   0   1   0   0   1   0   1   0   1   0   0   0   0   1   0   0   1   0   1   0   1   0   0
3   0   0   1   0   0   1   0   1   0   1   0   0   0   0   1   0   0   1   0   1   0   1   0   0
4   0   0   1   0   0   1   0   1   0   1   0   0   0   0   1   0   0   1   0   1   0   1   0   0
5   0   0   1   0   0   1   0   1   0   1   0   0   0   0   1   0   0   1   0   1   0   1   0   0
6   0   0   1   0   0   1   0   1   0   1   0   0   0   0   1   0   0   1   0   1   0   1   0   0

所以我写了以下代码:

NAMES.Q = paste(rep("Q",8), c(1:8), sep="") 
DAT[ which(DAT[NAMES.Q]=="NULL"),]<- NA # to set to NA skipped questions
NAMES.q  = paste(rep("q",8), c(1:8), sep="") 

以下代码是将字符串转换为01 数值。

q1 <- read.csv(text = as.character(DAT[,"Q1"]), strip.white = TRUE)
q2 <- read.csv(text = as.character(DAT[,"Q2"]), strip.white = TRUE)
q3 <- read.csv(text = as.character(DAT[,"Q3"]), strip.white = TRUE)
q4 <- read.csv(text = as.character(DAT[,"Q4"]), strip.white = TRUE)
q5 <- read.csv(text = as.character(DAT[,"Q5"]), strip.white = TRUE)
q6 <- read.csv(text = as.character(DAT[,"Q6"]), strip.white = TRUE)
q7 <- read.csv(text = as.character(DAT[,"Q7"]), strip.white = TRUE)
q8 <- read.csv(text = as.character(DAT[,"Q8"]), strip.white = TRUE)
names(q1) = paste("q1", 1:3, sep = "")
names(q2) = paste("q2", 1:3, sep = "")
names(q3) = paste("q3", 1:3, sep = "")
names(q4) = paste("q4", 1:3, sep = "")
names(q5) = paste("q5", 1:3, sep = "")
names(q6) = paste("q6", 1:3, sep = "")
names(q7) = paste("q7", 1:3, sep = "")
names(q8) = paste("q8", 1:3, sep = "")
q1[is.na(q1)] <- 0
q2[is.na(q2)] <- 0
q3[is.na(q3)] <- 0
q4[is.na(q4)] <- 0
q5[is.na(q5)] <- 0
q6[is.na(q6)] <- 0
q7[is.na(q7)] <- 0
q8[is.na(q8)] <- 0
qs<-cbind(q1, q2, q3, q4, q5, q6, q7, q8) 

代码有效,但我发现它很难阅读和维护。

您是否建议在我的主要data.frame (DAT) 中写入此信息而不创建新的data.frame

【问题讨论】:

  • 您不是在自己的方法中创建了很多新的数据框吗? “不创建新的 data.frame”是什么意思?
  • @vaettchen 确切地说,我正在创建额外的(不必要的?)数据框,因为我不知道该怎么做。

标签: string r for-loop dataframe performance


【解决方案1】:

首先,使用read.table 读取数据。 read.table 中的默认字段分隔符是“空白”,即分隔符连接的“Q”列之间。

然后您可以使用包splitstackshapeconcat.split.multiple 中的函数来拆分连接的列。通过不指定split.cols,需要拆分的列,所有列被拆分。每列中使用的默认分隔符 (seps) 为 ,。生成的数据框的默认形状 (direction) 为“宽”。因此,在这种情况下,您只需提供数据框的名称。

df <- read.table(text="  Q1  Q2  Q3  Q4  Q5  Q6  Q7  Q8
1 ,,1 ,,1 ,1, 1,, ,,1 ,,1 ,1, 1,,
2 ,,1 ,,1 ,1, 1,, ,,1 ,,1 ,1, 1,,
3 ,,1 ,,1 ,1, 1,, ,,1 ,,1 ,1, 1,,
4 ,,1 ,,1 ,1, 1,, ,,1 ,,1 ,1, 1,,
5 ,,1 ,,1 ,1, 1,, ,,1 ,,1 ,1, 1,,
6 ,,1 ,,1 ,1, 1,, ,,1 ,,1 ,1, 1,,", header=TRUE)

library(splitstackshape)

# split columns
df2 <- concat.split.multiple(df)

# or explicitly writing out the arguments
df2 <- concat.split.multiple(data = df, split.cols = names(df), seps = ",")

# replace NA with 0
df2[is.na(df2)] <- 0
df2

#   Q1_1 Q1_2 Q1_3 Q2_1 Q2_2 Q2_3 Q3_1 Q3_2 Q3_3 Q4_1 Q4_2 Q4_3 Q5_1 Q5_2 Q5_3 Q6_1 Q6_2 Q6_3 Q7_1 Q7_2 Q7_3 Q8_1 Q8_2 Q8_3
# 1    0    0    1    0    0    1    0    1    0    1    0    0    0    0    1    0    0    1    0    1    0    1    0    0
# 2    0    0    1    0    0    1    0    1    0    1    0    0    0    0    1    0    0    1    0    1    0    1    0    0
# 3    0    0    1    0    0    1    0    1    0    1    0    0    0    0    1    0    0    1    0    1    0    1    0    0
# 4    0    0    1    0    0    1    0    1    0    1    0    0    0    0    1    0    0    1    0    1    0    1    0    0
# 5    0    0    1    0    0    1    0    1    0    1    0    0    0    0    1    0    0    1    0    1    0    1    0    0
# 6    0    0    1    0    0    1    0    1    0    1    0    0    0    0    1    0    0    1    0    1    0    1    0    0

【讨论】:

  • 这是一个很好的建议。我不知道这个splitstackshape 包!在我的情况下它可能非常有用。但是,我尝试运行它并收到以下错误:Error in data.frame(..., check.names = FALSE) : arguments imply differing number of rows: 0, 15000。我不确定,但可能是我的数据太长(17,000)。
  • 很难说哪里出了问题。它与您提供的示例数据的格式很好地配合...
  • 我缩短了数据,它起到了一种魅力。非常优雅的解决方案!
  • 很高兴听到!你的原始数据有多大? ping 软件包的维护者并描述这个潜在的“问题”可能是值得的。
  • @inarts,我在一个包含 10000 个示例数据副本(即 60000 行)的数据框中尝试了该函数。它工作得很好。也许您需要检查您的原始数据。也许示例数据中没有捕捉到一些特性?干杯!
【解决方案2】:

使用strsplit 代替read.csv。添加一些lapply 循环,一切就绪。

DF <- read.table(text="  Q1  Q2  Q3  Q4  Q5  Q6  Q7  Q8
1 ,,1 ,,1 ,1, 1,, ,,1 ,,1 ,1, 1,,
2 ,,1 ,,1 ,1, 1,, ,,1 ,,1 ,1, 1,,
3 ,,1 ,,1 ,1, 1,, ,,1 ,,1 ,1, 1,,
4 ,,1 ,,1 ,1, 1,, ,,1 ,,1 ,1, 1,,
5 ,,1 ,,1 ,1, 1,, ,,1 ,,1 ,1, 1,,
6 ,,1 ,,1 ,1, 1,, ,,1 ,,1 ,1, 1,,", header=TRUE)

DF2 <- do.call(cbind.data.frame, lapply(DF, function(x) {
  res <- strsplit(x, ",")
  res <- lapply(res, as.numeric)
  res <- do.call(rbind, res)
  res[is.na(res)] <- 0  
  res
  }))

#  Q1.1 Q1.2 Q1.3 Q2.1 Q2.2 Q2.3 Q3.1 Q3.2 Q4.1 Q4.2 Q5.1 Q5.2 Q5.3 Q6.1 Q6.2 Q6.3 Q7.1 Q7.2 Q8.1 Q8.2
#1    0    0    1    0    0    1    0    1    1    0    0    0    1    0    0    1    0    1    1    0
#2    0    0    1    0    0    1    0    1    1    0    0    0    1    0    0    1    0    1    1    0
#3    0    0    1    0    0    1    0    1    1    0    0    0    1    0    0    1    0    1    1    0
#4    0    0    1    0    0    1    0    1    1    0    0    0    1    0    0    1    0    1    1    0
#5    0    0    1    0    0    1    0    1    1    0    0    0    1    0    0    1    0    1    1    0
#6    0    0    1    0    0    1    0    1    1    0    0    0    1    0    0    1    0    1    1    0

【讨论】:

  • 我已经按照您的示例进行操作,并且完全按照您的说明进行操作。很好的解决方案!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-16
  • 1970-01-01
  • 2013-01-19
  • 1970-01-01
  • 1970-01-01
  • 2019-06-29
相关资源
最近更新 更多