R:找到匹配的字符串,然后复制行
我有一个多步骤的问题。第一步:将一个字符串(df1)中的文本从一列匹配到另一个列范围(df2)。没有列匹配的顺序,匹配可能发生在范围内的任何位置。找到匹配项后,将df2行匹配项复制到df1中。最后,对整个列重复此操作R:找到匹配的字符串,然后复制行,r,formatting,match,data-management,R,Formatting,Match,Data Management,我有一个多步骤的问题。第一步:将一个字符串(df1)中的文本从一列匹配到另一个列范围(df2)。没有列匹配的顺序,匹配可能发生在范围内的任何位置。找到匹配项后,将df2行匹配项复制到df1中。最后,对整个列重复此操作 df1= structure(list(Assay = c("ATG_AR_trans_up","NVS_PXR_cis","BSK_VCAM1_up"), p.value = c(0.01,0.05,0.0001)), .Names = c("Assay", "p.value")
df1= structure(list(Assay = c("ATG_AR_trans_up","NVS_PXR_cis","BSK_VCAM1_up"), p.value = c(0.01,0.05,0.0001)), .Names = c("Assay", "p.value"),row.names = c(NA, 3L), class = "data.frame")
df1
Assay p.value
ATG_AR_trans_up 0.01
NVS_hPXR 0.065
BSK_VCAM1_up 0.001
df2=structure(list(GeneID = c("AR", "VACM1", "TR", "ER", "PXR"), Assay1= c("ATG_ARE_cis", "BSK_hEDG_VCAM1", "NVS_TR_tran", "ATG_ER_UP", "NVS_PXRE_UP"), Assay2= c("ATG_AR_trans_up", "BSK_BE3K_VCAM1", "NA", "ATG_ERE_cis", "ATG_PXRE_cis"), Assay3= c("NVS_AR_trans", "BSK_VCAM1_UP", "NA", "NVS_ERa_CIS", "NVS_PXR_cis"), Assay4= c("Tox21_AR_ARE","NA", "NA", "Tox21_ERaERb_lig", "NA")), .Names = c("GeneID", "Assay1", "Assay2", "Assay3", "Assay4"),row.names = c(NA, 5L), class = "data.frame")
df2
GeneID Assay1 Assay 2 Assay3
AR ATG_ARE_cis NVS_hAR ATG_AR_trans_up
VACM1 BSK_hEGF_CAM1 BSK_VCAM1_up BSK_VCAM1_down
TR NVS_TR_tran NA NA
ER ATG_ER_UP ATG_ERE_cis NVS_ERa_CIS
PXR ATG_PXR_down ATG_PXRE_cis NVS_hPXR
本质上成为
df
Assay p.value GeneID Assay1 Assay2 Assay3
ATG_AR_trans_up 0.01 AR ATG_ARE_cis NVS_hAR ATG_AR_trans_up
NVS_hPXR 0.065 PXR ATG_PXR_down ATG_PXRE_cis NVS_hPXR
BSK_VCAM1_up 0.001 VCAM1 BSK_hEGF_CAM1 BSK_VCAM1_up BSK_VCAM1_down
为简洁起见,我大幅缩短了df,但一次匹配大约需要88次分析和4000多行(大约有30行)。因此,我最初的直觉是循环,但有人告诉我,grep
可能是一个有用的包(尽管它不适用于R3.2.2)。任何帮助都将不胜感激。在用户澄清后编辑:
我刚刚创建了一个三重for循环来检查你的值。基本上,它所做的是寻找一个匹配。它通过循环遍历所有列和该列中的所有值来实现这一点
然而,我的代码还不完美(也是R的初学者),我只是想发布它,以便我们可以一起解决一些问题:)
所以我首先将数据转换为data.frame。之后,我创建了一个空的输出,然后根据找到的匹配项填充该输出
此方法的改进在于,使用此解决方案,函数append还将追加列名,这将导致多个无用的列名
df3 <- as.data.frame(df1)
df4 <- as.data.frame(df2)
output <- data.frame()
for(j in 1:nrow(df3)) {
match <- FALSE
for(i in 2:(ncol(df4))) {
for(p in 1:nrow(df4)) {
if((df3[j, 1] == df4[p, i]) && (match == FALSE)) {
output <- append(output, c(df3[j, ], df4[j, ]))
match <- TRUE
}
}
}
}
df3由于您是R新手,我认为您是对的,最直观的方法是使用for循环。这不是最简洁或最有效的方法,但应该清楚发生了什么
# Creating example data
df1 <- as.data.frame(matrix(data=c("aa", "bb", "ee", .9, .5, .7), nrow=3))
names(df1) <- c("assay", "p")
df2 <- as.data.frame(matrix(data=c("G1", "G2", "aa", "dd", "bb", "ee", "cc", "ff"), nrow=2))
names(df2) <- c("GeneID", "assay1", "assay2", "assay3")
# Building a dataframe to store output
df3 <- as.data.frame(matrix(data=NA, nrow=dim(df1)[1], ncol=dim(df2)[2]))
names(df3) <- names(df2)
# Populating dataframe with output
for(i in 1:dim(df1)[1]){
index <- which(df2==as.character(df1$assay[i]), arr.ind = TRUE)[1]
for(j in 1:dim(df3)[2]){
df3[i,j] <- as.character(df2[index,j])
}
}
df <- cbind(df1, df3)
#创建示例数据
df1这可以通过整形轻松完成。我把所有的分析都放进所有的瓶盖里,因为那会把匹配搞砸
library(dplyr)
library(tidyr)
library(stringi)
df2_ID = df %>% mutate(new_ID = 1:n() )
result =
df2_ID %>%
select(new_ID, Assay1:Assay85) %>%
gather(assay_number, Assay, Assay1:Assay85) %>%
mutate(Assay =
Assay %>%
iconv(to = "ASCII") %>%
stri_trans_toupper) %>%
inner_join(df1 %>%
mutate(Assay =
Assay %>%
iconv(to = "ASCII") %>%
stri_trans_toupper)) %>%
inner_join(df2_ID)
由于OP对grep
解决方案感兴趣,另一种方法是
asDF2 <- apply(df2, 1, function(r) do.call(paste, as.list(r)))
do.call(rbind, lapply(1:nrow(df1),
function(i){
matchIX <- grepl(df1$Assay[i], asDF2, ignore.case=T)
if(any(matchIX))
cbind(df1[i, ], df2[matchIX, ])
}))
请注意,上述变体可以将df2
中的多行匹配到df1
注意
为了测试,我将新行添加到原始数据帧中,如下所示
df1 <- rbind(df1, data.frame(Assay="NoMatch", p.value=.2))
df2 <- rbind(df2,
data.frame(GeneID="My", Assay1="NVS_PXR_cis", Assay2="NA", Assay3="NA", Assay4="NA"))
df1假设没有与df1中的条目对应的任何重复条目。以下是您问题的解决方案:
assay <-as.matrix(df1[,1])
m1 <- as.numeric(sapply(assay, function(x){grep(x,df2[,2], ignore.case = T)}, simplify = FALSE))
m2 <- as.numeric(sapply(assay, function(x){grep(x,df2[,3], ignore.case = T)}, simplify = FALSE))
m3 <- as.numeric(sapply(assay, function(x){grep(x,df2[,4], ignore.case = T)}, simplify = FALSE))
m4 <- as.numeric(sapply(assay, function(x){grep(x,df2[,5], ignore.case = T)}, simplify = FALSE))
m1[is.na(m1)] <- 0
m2[is.na(m2)] <- 0
m3[is.na(m3)] <- 0
m4[is.na(m4)] <- 0
m0 <- (m1+m2+m3+m4)
df <- NULL
for(i in 1:nrow(df1){
df3 = cbind(df1[i,],df2[m0[i],])
df = rbind(df,df3)
}
您的示例太小。尝试添加更多匹配项以显示所需的输出。确定。我试试看。如果可以接受编辑,请告诉我您可以编辑问题。您还应该使用dput
存放示例,这样人们就不必手动复制dfs。我添加了数据帧。希望这能让它更容易理解…虽然我觉得我让它更混乱。谢谢,但我也需要添加匹配的条件。可能是因为我问问题的方式不好。我尝试添加数据帧以使其更容易。这个问题的框架是否仍然很糟糕?“我想是我把事情弄得更糟了。”艾斐特,我认为你的编辑很清楚;这绝对没有让事情变得更糟。谢谢你添加的信息!问题中不清楚的部分是,行找到匹配项的条件是什么。在前两个输出行中,我注意到“Assay”和“Assay3”中有一个匹配项。但在您的第三排,我注意到“Assay”和“Assay 2”匹配。那么,它是否应该在第二个数据帧的三个“分析”中找到一个匹配项呢?是的。没有特定的列匹配顺序。我只需要在任何分析列中找到一个匹配项(实际上有88个,但为了便于示例,我认为3/4就足够了)。这是你应该提到的,哈哈。我在考虑做一个for循环,但是如果你有88列,那么做88个if-else语句将是一种非常糟糕的编码方式。谢谢!抱歉,我花了一点时间运行代码,但我得到了!!等待在我看来,它似乎在工作,但并没有找到所有匹配项。有什么想法可能会出错吗?这取决于数据帧的完整结构。您可以尝试将for循环中的which语句替换为which((as.character(df2)==as.character(df1$assay[i]),arr.ind=TRUE)[1]
我收到一个语法错误,无法解决它:“error:unexpected”,“in:”for(i in 1:dim(df1)[1]){索引太棒了。我如何/在哪里保存它?我已经编辑过,所以答案保存在一个名为result的数据框中。谢谢!不过仍然有问题。我只在结果中获得了46个变量中的19个。此外,我还收到了一条警告消息:“警告消息:度量变量之间的属性不相同;它们将被删除”有什么想法吗?这里发生的事情(如我的回答)是,应该匹配的元素有一些微妙的地方导致它们不匹配。可能是大小写问题、不知道存在的前导或尾随空格,或者不同的数据类型(例如,有些存储为字符,另一些存储为因子)。但由于某些原因,您认为应该匹配的单元格实际上并不匹配。要检查这一点,请找到一个未正确提取的匹配项,并检查df1和df2中的相关条目是否与前面的一致。其他可能导致问题的内容是“不可见的”字符。转换为ascii有时会有帮助。你太棒了。它工作了50%。我基本上必须为两组不同的数据帧运行这段代码两次。第一组最终工作了,但当我运行第二组时,我得到了错误:“data.frame中的错误(…,check.names=FALSE):参数意味着不同的行数:1,0 7停止(gettextf(“参数表示不同的行数:%s”),粘贴(唯一(nrows),collapse=“,”),domain=NA)6数据帧(…,check.names=FALSE)5 cbind(deparse.level,…)4 cbind(p.MDRatT[i,],AmigoDEV[grepl(p.MDRatT$Assay[i],data.frame(t(AmigoDEV,stringsafactors=F),ignore.case=t),]))3乐趣(X[[i],…)2 lappy(1)nrow(p.MDRatT),function(i)cbind(p.MDRatT[i,],AmigoDEV[grepl(p.MDRatT$Assay[i],data.frame(t(AmigoDEV),stringsAsFactors=F),ignor
assay <-as.matrix(df1[,1])
m1 <- as.numeric(sapply(assay, function(x){grep(x,df2[,2], ignore.case = T)}, simplify = FALSE))
m2 <- as.numeric(sapply(assay, function(x){grep(x,df2[,3], ignore.case = T)}, simplify = FALSE))
m3 <- as.numeric(sapply(assay, function(x){grep(x,df2[,4], ignore.case = T)}, simplify = FALSE))
m4 <- as.numeric(sapply(assay, function(x){grep(x,df2[,5], ignore.case = T)}, simplify = FALSE))
m1[is.na(m1)] <- 0
m2[is.na(m2)] <- 0
m3[is.na(m3)] <- 0
m4[is.na(m4)] <- 0
m0 <- (m1+m2+m3+m4)
df <- NULL
for(i in 1:nrow(df1){
df3 = cbind(df1[i,],df2[m0[i],])
df = rbind(df,df3)
}
assay <-as.matrix(df1[,1])
# Storing Assay column in a list
m <- vector('list',ncol(df2[, 2:ncol(df2)]))
for(i in 1:length(m)){
m[[i]] <- as.numeric(sapply(assay, function(x){grep(x,df2[,(i+1)], ignore.case = T)}, simplify = FALSE))
}
# Getting row subscript for df2
m1 <- as.data.frame(m)
m1[is.na(m1)] <- 0
m2 <- rowSums(m1)
df <- NULL
for(i in 1:nrow(df1)){
df3 = cbind(df1[i,],df2[m2[i],])
df = rbind(df,df3)
}