在R中循环以匹配并从其他工作表中提取数据

时间:2016-11-28 07:32:03

标签: r

我是R的新手所以请耐心等待。我有两个数据帧dfA和dfB。

dfA

   Type
Test1 11000
11000 Test2
Test3 11000
11000 Test4
Test5 11001
Test6 11002
Test7 11003
Test8 11004
Test9 11004
Test10 11006

DFB

Asset NO    No
11000       1
11001       2
11002       3
11003       4
11004       5
11005       6
11006       7
11007       8
11008       9
11009      10

Desired Out Put

Type         No
Test1 11000   1
11000 Test2   1
Test3 11000   1
11000 Test4   1
Test5 11001   2
Test6 11002   3
Test7 11003   4
Test8 11004   5
Test9 11004   5
Test10 11006  7

我相信forloop和grepl是必需的。如果有人可以帮助我如何记下forloop会有很大的帮助。

5 个答案:

答案 0 :(得分:1)

如果dfB$No只是一个行号,我只会做

match(as.integer(sub(".*(\\b\\d+\\b).*", "\\1", dfA$Type)), dfB$AssetNO)
## [1] 1 1 1 1 2 3 4 5 5 7

这将仅捕获dfA$Type中的整数(以单词绑定为界),然后匹配回dfB$AssetNO

否则,只需稍加修改即可

indx <- match(as.integer(sub(".*(\\b\\d+\\b).*", "\\1", dfA$Type)), dfB$AssetNO)
dfB[indx, "No"]
## [1] 1 1 1 1 2 3 4 5 5 7

作为旁注,您的数据似乎搞砸了。您可能应该尝试以一致的格式记录数据。通过这种方式,可以避免使用正则表达式,从而大大提高性能。

答案 1 :(得分:0)

希望这有帮助

Type <- c("Test1 11000","11000 Test2","Test3 11000","11000 Test4","Test5 11001",
          "Test6 11002","Test7 11003","Test8 11004","Test9 11004","Test10 11006")

Asset_NO <- seq(11000,11009,1)   
No <- seq(1,10,1)

dfA <- data.frame(Type)
dfB <- data.frame(Asset_NO,No)

split <- str_split(dfA$Type, " ")
v <- c(NULL)

for (i in 1:length(split)) {
  f <- sapply(split, "[",1)
  s <- sapply(split, "[",2)
  #v <- ifelse(grepl("Test",f), s, f)
   v <- ifelse(grepl("[a-zA-Z]",f), s, f) #As per the new cooment
}

dfA$Asset_NO <- v
dfA$Asset_NO <- as.numeric(dfA$Asset_NO)

m <- merge(dfA, dfB, by="Asset_NO")
m

输出

    Asset_NO         Type No
1     11000  Test1 11000  1
2     11000  11000 Test2  1
3     11000  Test3 11000  1
4     11000  11000 Test4  1
5     11001  Test5 11001  2
6     11002  Test6 11002  3
7     11003  Test7 11003  4
8     11004  Test8 11004  5
9     11004  Test9 11004  5
10    11006 Test10 11006  7

答案 2 :(得分:0)

我首先为名为dfA的{​​{1}}创建一个新列:

并使用NEW将所有字​​母替换为空字符串gsub。这给了我一个两个数字的向量,但我通过对数字进行排序来寻找有意义的数字,一个是索引,另一个是根据""Asset_NO的列的值/ p>

dfB

我确保这些都是数字形式,所以比较苹果和橘子。

dfA$NEW = NA
for(i in 1:nrow(dfA)){
    temp = as.numeric(strsplit(gsub("[[:alpha:]]", "", dfA$Type[i]), split = " ")[[1]])
    dfA$NEW[i] = (sort(temp, decreasing = T)[1])
}

然后我需要做的就是合并它们。

dfB$Asset_NO = as.numeric(dfB$Asset_NO)

答案 3 :(得分:0)

您可以使用Asset_NO和简单的dfB语句以及gregexprifelse中创建列merge,如下所示,

dfA$Asset_NO <- ifelse(sapply(gregexpr('[A-Za-z]+', dfA$Type), '[', 1) > 1, 
                          gsub('\\s+.*', '', dfA$Type), gsub('.*\\s+', '', dfA$Type))

merge(dfA, dfB)

#   Asset_NO         Type No
#1     11000  Test1 11000  1
#2     11000  11000 Test2  1
#3     11000  Test3 11000  1
#4     11000  11000 Test4  1
#5     11001  Test5 11001  2
#6     11002  Test6 11002  3
#7     11003  Test7 11003  4
#8     11004  Test8 11004  5
#9     11004  Test9 11004  5
#10    11006 Test10 11006  7

答案 4 :(得分:0)

这是使用data.tablestringr的另一种方法:

library(data.table)
dfA[, Asset := as.integer(stringr::str_extract(Type, "(^\\d{5})|(\\d{5}$)"))]
dfB[dfA, on = "Asset", .(Type, No)]
#            Type No
# 1:  Test1 11000  1
# 2:  11000 Test2  1
# 3:  Test3 11000  1
# 4:  11000 Test4  1
# 5:  Test5 11001  2
# 6:  Test6 11002  3
# 7:  Test7 11003  4
# 8:  Test8 11004  5
# 9:  Test9 11004  5
#10: Test10 11006  7
#11:   Test111000  1
#12:   11000Test2  1
#13:   Test311000  1
#14:   11000Test4  1
#15:   Test511001  2
#16:   Test611002  3
#17:   Test711003  4
#18:   Test811004  5
#19:   Test911004  5
#20:  Test1011006  7

请注意,所有答案在用于从Type中提取资产编号的正则表达式上有所不同。这是由于原始问题中提供的规格较差。

此处使用的正则表达式假设资产编号始终由五位数组成,Type以资产编号开头或结尾。这与任何单词边界无关,因此也适用于Type中不包含空格的情况。

将提取的资产编号分配到新列dfA后,dfB上的Asset加入。

讨论

我刚刚意识到OP在各种评论中都披露了重要信息:

  

@etienne这是一行没有列所以理想情况下一个单词'11000Test2''Test311000'因此使用grepl和搜索第二个df的原因是因为数字不符合需要使用搜索来匹配,否则可能删除了缩写并进行了匹配。

  

不能将grepl用作“test”,因为所有Type都没有被提及为Test这只是真实数据中的一个例子。因此基本上需要用数字进行搜索,所以从dfB搜索第一个数字并将其与dfA匹配,然后从dfB的b列获得输出,如果没有匹配则从第2个df中选择第2个数字,依此类推......

但是,只要OP不能提供更实际的生产数据样本,只要资产数量可以通过正则表达式从Type无法提取,就无需查询如果Type中存在匹配项,则为每个给定的资产编号。