来自存储在可变长度连接字符串中的数据的R数据帧

时间:2016-07-28 10:54:04

标签: r

我有一个数据框,其中包含许多针对由|:

分隔的id的功能
df = data.frame(id = c("1","2","3"), 
features = c("1|2|3","4|5","6|7")
)
df

我的目标是为每个功能添加一个列,并指示其存在的ID,例如

id | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
2 | 0 | 0 | 0 | 1 | 1 | 0 | 0 |
3 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |

这些功能存储在一个不同的表中,因此可以使用完整的可能功能列表,但如果我能动态生成这些功能会更好。

我的第一次尝试是使用一个非常慢的for循环,grepl()填充预先创建的矩阵'm',例如。

  for (i in 1:dim(df)[1]){
  print(i)
  if(grepl("1\\|", df$feature[i])) {m[i,1] <- 1}
  if(grepl("2\\|", df$feature[i])) {m[i,2] <- 1}
  if(grepl("3\\|", df$feature[i])) {m[i,3] <- 1}
  if(grepl("4\\|", df$feature[i])) {m[i,4] <- 1}
  if(grepl("5\\|", df$feature[i])) {m[i,5] <- 1}
  if(grepl("6\\|", df$feature[i])) {m[i,6] <- 1}
  if(grepl("7\\|", df$feature[i])) {m[i,7] <- 1}
}

当功能进入青少年时,忽略了我的正则表达式会崩溃的事实。在我需要运行它的~400,000行时,这非常慢。另外,我需要为每个id创建一个if()而不是动态地发生这种情况。

有没有办法用动态列生成更简洁地做到这一点?

2 个答案:

答案 0 :(得分:1)

要返回的最自然的对象是矩阵。这是在基础R中执行此操作的方法。

# split features column by pipe symbol  and subset result, dropping pipes
temp <- lapply(strsplit(as.character(df$features), split="|"), function(i) i[i != "|"])
# use %in% to return logical vector of desired length, convert to integer and rbind list
myMat <- do.call(rbind, lapply(temp, function(i) as.integer(1:7 %in% i)))
# add id as row names 
rownames(myMat) <- df$id

返回

myMat
  [,1] [,2] [,3] [,4] [,5] [,6] [,7]
1    1    1    1    0    0    0    0
2    0    0    0    1    1    0    0
3    0    0    0    0    0    1    1

如果您真的需要data.frame,可以使用

temp <- lapply(strsplit(as.character(df$features), split="|"), function(i) i[i != "|"])
myDf <- cbind(id=df$id, data.frame(do.call(rbind,
                                          lapply(temp, function(i) as.integer(1:7 %in% i)))))

返回

myDf
  df$id X1 X2 X3 X4 X5 X6 X7
1     1  1  1  1  0  0  0  0
2     2  0  0  0  1  1  0  0
3     3  0  0  0  0  0  1  1

答案 1 :(得分:0)

使用stringrdplyr的@Imo解决方案的不同实现,用于更紧凑的表示法,适用于从1到任意数字的功能:

# Split the feature column
temp <- str_split(df$features, "\\|") 

# Find the maximum feature
maximum <- as.numeric(max(do.call(rbind, temp), na.rm = T))

# Crate the final data frame
lapply(temp, function(i) as.integer(1:maximum %in% i)) %>%
    do.call(rbind,.) %>% 
    as.data.frame() %>%
    cbind(df, .)

产生:

  id features V1 V2 V3 V4 V5 V6 V7
1  1    1|2|3  1  1  1  0  0  0  0
2  2      4|5  0  0  0  1  1  0  0
3  3      6|7  0  0  0  0  0  1  1