替换 r 中大型数据框中的多个文本字符串

Replace multiple strings of text in a large dataframe in r

我一直在尝试使用 gsub 在边缘列表中用简单的整数替换标识符键。边缘列表由个人和他们的连接列表组成(长度因个人而异)。不幸的是,由于我的数据集超过 30 万行(因此需要 30 万次以上的搜索和替换操作),运行 迭代它需要将近一周的时间才能 运行 通过。当前代码能够产生所需的输出,但我正试图找到一种更有效的方法。有谁知道产生类似输出的更好方法?我当前的代码、一些假设的示例数据和示例输出如下:

示例数据:

Person  Connection_list
ENJAK   IDFJA, FDAKD, AODMK
JBJDF   KJDFA
LAFMD   JBJDF, KAOJD, ENJAK,FKJSE,IDFJA, AKSKE, FNAFJ, KJDFA, ATNFN, ADOFA, ODIJA, AODMK, NAGJA, NFAKD, FDAKD, KDSFN
ADOFA   JDFKA, KAOJD, NAGJA
KJDFA   ENJAK, ATNFN, NFAKD, ADOFA, AODMK, JDFKA, LAFMD, ODIJA, FNAFJ, KDSFN, JBJDF, FJKAS, FKJSE, AKSKE, NAGJA
IDFJA   AKSKE, KJDFA, FJKAS, ADOFA
KDSFN   KAOJD, ADOFA, AKSKE, FDAKD, NFAKD, FKJSE, NAGJA, JDFKA, ODIJA, FJKAS, ATNFN, JBJDF, FNAFJ, KJDFA, LAFMD, ENJAK
AKSKE   ADOFA, ODIJA, KAOJD, JBJDF, ENJAK, AODMK, FDAKD, IDFJA, NAGJA, KJDFA
NAGJA   KAOJD, AKSKE
ODIJA   ADOFA, FDAKD, FKJSE, ATNFN, IDFJA, NAGJA, KAOJD
FKJSE   JBJDF, NAGJA, KDSFN, KAOJD, LAFMD, KJDFA, NFAKD, FDAKD, ENJAK, ATNFN, FNAFJ, ODIJA, ADOFA, AODMK, FJKAS, AKSKE, IDFJA
FDAKD   ADOFA, ODIJA, FKJSE, NAGJA, NFAKD, KJDFA, JBJDF, ATNFN, AODMK, AKSKE, KDSFN, JDFKA, LAFMD
NFAKD   ADOFA, KJDFA, AKSKE, KDSFN, FJKAS, JBJDF, JDFKA
FJKAS   FKJSE, AKSKE, FDAKD, NAGJA, ADOFA, ENJAK, FNAFJ, KDSFN, NFAKD, ATNFN, AODMK, KAOJD, JBJDF, JDFKA, LAFMD, IDFJA
JDFKA   AKSKE, KJDFA, IDFJA
ATNFN   AODMK, IDFJA, AKSKE
KAOJD   ENJAK, FJKAS, FKJSE, AKSKE, NFAKD, LAFMD, JDFKA, KDSFN, ODIJA
AODMK   AKSKE, FNAFJ, KAOJD, JDFKA, LAFMD, FDAKD, KDSFN, ENJAK, FJKAS, JBJDF, FKJSE, IDFJA, ATNFN
FNAFJ   JBJDF, ADOFA, NFAKD, ODIJA, KAOJD, FKJSE, LAFMD, AKSKE, KDSFN, IDFJA, FNAFJ, ENJAK 

当前代码:

for (i in 1:dim(data)[1]){
  data$key[i] <- i
  data[,2] <- gsub(data[i,1],as.character(i),data[,2])
}

Desired/current 输出:

key  Person Connection_list
1   ENJAK   6,12,1,18
2   JBJDF   5
3   LAFMD   2,17,3,1,11,6,8,19,5,16,4,10,18,9,13,12,7
4   ADOFA   15,17,9,4
5   KJDFA   1,5,16,13,4,18,15,3,10,19,7,2,14,11,8,9
6   IDFJA   8,5,14,4,6
7   KDSFN   17,4,8,12,13,11,9,15,7,10,14,16,2,19,5,3,1
8   AKSKE   4,10,17,2,1,18,12,6,9,5
9   NAGJA   17,8
10  ODIJA   4,12,11,16,6,9,17
11  FKJSE   2,9,7,17,3,5,13,12,11,1,16,19,10,4,18,14,8,6
12  FDAKD   4,10,11,9,12,13,5,2,16,18,8,7,15,3
13  NFAKD   4,5,8,7,14,2,15
14  FJKAS   11,8,14,12,9,4,1,19,7,13,16,18,17,2,15,3,6
15  JDFKA   8,5,15,6
16  ATNFN   16,18,6,8
17  KAOJD   1,14,11,8,13,3,15,7,10
18  AODMK   8,19,17,15,3,12,7,1,14,2,11,6,16,18
19  FNAFJ   2,4,13,10,17,11,3,8,7,6,19,1

不是解决您问题的明确代码,而是我会使用的策略。

如果我没看错的话,Person 是一个唯一标识符,Connection_list 是人与人之间的界限。如果您的值是因子,并且您需要在分析流中进一步计算数值,则实际上没有必要显式转换为整数,您可以使用因子整数值。

首先,我会将 Connection_list 转换为多列,例如此处讨论:Split column into multiple columns R

然后,在完成并且您的列被识别为包含因子值之后,

aframe2 <- as.data.frame(lapply(aframe1, factor))

您应该能够使用 as.numeric(as.character(f)).

中的内容从这些因素中检索数值

我最终以迂回的方式解决了这个问题。因为每个用户都有不同长度的朋友,所以我使用 dplyr 包来拆分每一行并对每一行应用拆分函数(使用 stringr 包):制作一个 'long' edgelist ,然后在将列表转换为它们的等效因子后,我将结果重新组合回原始格式。重组的代码很乱,我相信可能有更有效的方法,但代码看起来像这样:

library(dplyr)
library(stringr)
# User defined split fuction
longedge <- function(df){
  user <- df$user_id
  cnx <- df$friends
  split <- as.data.frame(ifelse(cnx=="",NA,str_split(cnx,", ")))
  combine <- as.data.frame(cbind(user,split),stringAsFactors=FALSE)
  colnames(combine) <- c("user_id", "friend")
  return(combine)
}
# Creating long edgelist
edgelist <- edgelist %>%
  rowwise() %>%
  do(longedge(.)) %>%
  rbind()
# Convert to number
edgelist$friend <- as.numeric(as.factor(edgelist$friend))

# Create count of No. of connections
edgelist1 <- edgelist %>%
  group_by(user_id) %>%
  summarize(friend_count=n())

# Recreate 'wide' connection list
friend_list <- rep(NA,dim(edgelist1)[1])
for (i in 1:dim(edgelist1)[1]){
  if(i==1){j<-1}
  x <- j + edgelist1$friend_count[i]
  friend_list[i] <- as.character(edgelist$friend[j])
  j <- j+1
  while(j < x ){
    friend_list[i] <- paste(friend_list[i],edgelist$friend[j],sep=", ")
    j <- j+1
  }
}

# Recombine
edgelist1 <- cbind(edgelist1,friend_list)