如何在R中执行vlookup并填写(如在Excel中)?

use*_*810 76 lookup r

我有一个大约105000行和30列的数据集.我有一个分类变量,我想将它分配给一个数字.在Excel中,我可能会做一些事情VLOOKUP并填写.

我将如何做同样的事情R

基本上,我所拥有的是一个HouseType变量,我需要计算HouseTypeNo.以下是一些示例数据:

HouseType HouseTypeNo
Semi            1
Single          2
Row             3
Single          2
Apartment       4
Apartment       4
Row             3
Run Code Online (Sandbox Code Playgroud)

Ben*_*Ben 108

如果我正确理解你的问题,这里有四种方法来做相当于Excel的操作VLOOKUP并使用R以下方法填写:

# load sample data from Q
hous <- read.table(header = TRUE, 
                   stringsAsFactors = FALSE, 
text="HouseType HouseTypeNo
Semi            1
Single          2
Row             3
Single          2
Apartment       4
Apartment       4
Row             3")

# create a toy large table with a 'HouseType' column 
# but no 'HouseTypeNo' column (yet)
largetable <- data.frame(HouseType = as.character(sample(unique(hous$HouseType), 1000, replace = TRUE)), stringsAsFactors = FALSE)

# create a lookup table to get the numbers to fill
# the large table
lookup <- unique(hous)
  HouseType HouseTypeNo
1      Semi           1
2    Single           2
3       Row           3
5 Apartment           4
Run Code Online (Sandbox Code Playgroud)

这里有四种方法,填补了HouseTypeNolargetable使用中的值lookup表:

merge在基地:

# 1. using base 
base1 <- (merge(lookup, largetable, by = 'HouseType'))
Run Code Online (Sandbox Code Playgroud)

在base中使用命名向量的第二种方法:

# 2. using base and a named vector
housenames <- as.numeric(1:length(unique(hous$HouseType)))
names(housenames) <- unique(hous$HouseType)

base2 <- data.frame(HouseType = largetable$HouseType,
                    HouseTypeNo = (housenames[largetable$HouseType]))
Run Code Online (Sandbox Code Playgroud)

三,使用plyr包:

# 3. using the plyr package
library(plyr)
plyr1 <- join(largetable, lookup, by = "HouseType")
Run Code Online (Sandbox Code Playgroud)

第四,使用sqldf

# 4. using the sqldf package
library(sqldf)
sqldf1 <- sqldf("SELECT largetable.HouseType, lookup.HouseTypeNo
FROM largetable
INNER JOIN lookup
ON largetable.HouseType = lookup.HouseType")
Run Code Online (Sandbox Code Playgroud)

如果某些房屋类型可能largetable不存在,lookup那么将使用左连接:

sqldf("select * from largetable left join lookup using (HouseType)")
Run Code Online (Sandbox Code Playgroud)

也需要对其他解决方案进行相应的更改.

那是你想做的吗?让我知道您喜欢哪种方法,我会添加评论.

  • 我意识到这已经很晚了,但感谢您的帮助。我尝试了第一种方法和第二种方法。他们俩都工作得很好。再次感谢您回答问题! (2认同)
  • 我认为解决方案#2的作用只是因为在您的示例中,唯一值恰好按递增顺序排列(=第一个唯一名称为1,第二个唯一名称为2,依此类推).如果你添加'hous',请在*第二行*'HousType = ECII',HousTypeNo ='17'中查找完全错误. (2认同)
  • 很棒的帖子。感谢分享!#4 非常适合我的应用程序...加入两个非常大的 400MB 表。 (2认同)

Ben*_*ker 18

我想你也可以用match():

largetable$HouseTypeNo <- with(lookup,
                     HouseTypeNo[match(largetable$HouseType,
                                       HouseType)])
Run Code Online (Sandbox Code Playgroud)

如果我争抢的顺序,这仍然有效lookup.


mal*_*atr 10

我也喜欢使用qdapTools::lookup或简写二元运算符%l%.它与Excel vlookup的工作方式相同,但它接受与列号相对的名称参数

## Replicate Ben's data:
hous <- structure(list(HouseType = c("Semi", "Single", "Row", "Single", 
    "Apartment", "Apartment", "Row"), HouseTypeNo = c(1L, 2L, 3L, 
    2L, 4L, 4L, 3L)), .Names = c("HouseType", "HouseTypeNo"), 
    class = "data.frame", row.names = c(NA, -7L))


largetable <- data.frame(HouseType = as.character(sample(unique(hous$HouseType), 
    1000, replace = TRUE)), stringsAsFactors = FALSE)


## It's this simple:
library(qdapTools)
largetable[, 1] %l% hous
Run Code Online (Sandbox Code Playgroud)


ECI*_*CII 6

@ Ben的答案的解决方案#2在其他更通用的示例中不可重现.它碰巧在示例中给出了正确的查找,因为unique HouseTypein houses以递增的顺序出现.试试这个:

hous <- read.table(header = TRUE,   stringsAsFactors = FALSE,   text="HouseType HouseTypeNo
  Semi            1
  ECIIsHome       17
  Single          2
  Row             3
  Single          2
  Apartment       4
  Apartment       4
  Row             3")

largetable <- data.frame(HouseType = as.character(sample(unique(hous$HouseType), 1000, replace = TRUE)), stringsAsFactors = FALSE)
lookup <- unique(hous)
Run Code Online (Sandbox Code Playgroud)

Bens解决方案#2给出

housenames <- as.numeric(1:length(unique(hous$HouseType)))
names(housenames) <- unique(hous$HouseType)
base2 <- data.frame(HouseType = largetable$HouseType,
                    HouseTypeNo = (housenames[largetable$HouseType]))
Run Code Online (Sandbox Code Playgroud)

哪个

unique(base2$HouseTypeNo[ base2$HouseType=="ECIIsHome" ])
[1] 2
Run Code Online (Sandbox Code Playgroud)

当查找表中的正确答案为17时

正确的方法是

 hous <- read.table(header = TRUE,   stringsAsFactors = FALSE,   text="HouseType HouseTypeNo
      Semi            1
      ECIIsHome       17
      Single          2
      Row             3
      Single          2
      Apartment       4
      Apartment       4
      Row             3")

largetable <- data.frame(HouseType = as.character(sample(unique(hous$HouseType), 1000, replace = TRUE)), stringsAsFactors = FALSE)

housenames <- tapply(hous$HouseTypeNo, hous$HouseType, unique)
base2 <- data.frame(HouseType = largetable$HouseType,
  HouseTypeNo = (housenames[largetable$HouseType]))
Run Code Online (Sandbox Code Playgroud)

现在正确执行查找

unique(base2$HouseTypeNo[ base2$HouseType=="ECIIsHome" ])
ECIIsHome 
       17
Run Code Online (Sandbox Code Playgroud)

我试图编辑Bens答案,但由于我无法理解的原因而被拒绝.


Sim*_*mon 5

从...开始:

houses <- read.table(text="Semi            1
Single          2
Row             3
Single          2
Apartment       4
Apartment       4
Row             3",col.names=c("HouseType","HouseTypeNo"))
Run Code Online (Sandbox Code Playgroud)

... 您可以使用

as.numeric(factor(houses$HouseType))
Run Code Online (Sandbox Code Playgroud)

...为每种房屋类型提供唯一编号.你可以在这里看到结果:

> houses2 <- data.frame(houses,as.numeric(factor(houses$HouseType)))
> houses2
  HouseType HouseTypeNo as.numeric.factor.houses.HouseType..
1      Semi           1                                    3
2    Single           2                                    4
3       Row           3                                    2
4    Single           2                                    4
5 Apartment           4                                    1
6 Apartment           4                                    1
7       Row           3                                    2
Run Code Online (Sandbox Code Playgroud)

...所以你最终会在行上使用不同的数字(因为因子按字母顺序排序)但是相同的模式.

(编辑:这个答案中的剩余文本实际上是多余的.我read.table()想到要检查一下,事实证明,当它首先被读入数据帧时,已经将房屋$ HouseType变成了一个因素).

但是,您最好只将HouseType转换为一个因子,这将为您提供与HouseTypeNo相同的好处,但更容易解释,因为房屋类型是命名而不是编号,例如:

> houses3 <- houses
> houses3$HouseType <- factor(houses3$HouseType)
> houses3
  HouseType HouseTypeNo
1      Semi           1
2    Single           2
3       Row           3
4    Single           2
5 Apartment           4
6 Apartment           4
7       Row           3
> levels(houses3$HouseType)
[1] "Apartment" "Row"       "Semi"      "Single"  
Run Code Online (Sandbox Code Playgroud)


Sam*_*rke 5

mapvalues()您可以从 plyr 包中使用。

初始数据:

dat <- data.frame(HouseType = c("Semi", "Single", "Row", "Single", "Apartment", "Apartment", "Row"))

> dat
  HouseType
1      Semi
2    Single
3       Row
4    Single
5 Apartment
6 Apartment
7       Row
Run Code Online (Sandbox Code Playgroud)

查找/人行横道表:

lookup <- data.frame(type_text = c("Semi", "Single", "Row", "Apartment"), type_num = c(1, 2, 3, 4))
> lookup
  type_text type_num
1      Semi        1
2    Single        2
3       Row        3
4 Apartment        4
Run Code Online (Sandbox Code Playgroud)

创建新变量:

dat$house_type_num <- plyr::mapvalues(dat$HouseType, from = lookup$type_text, to = lookup$type_num)
Run Code Online (Sandbox Code Playgroud)

或者,对于简单的替换,您可以跳过创建长查找表并直接一步执行此操作:

dat$house_type_num <- plyr::mapvalues(dat$HouseType,
                                      from = c("Semi", "Single", "Row", "Apartment"),
                                      to = c(1, 2, 3, 4))
Run Code Online (Sandbox Code Playgroud)

结果:

> dat
  HouseType house_type_num
1      Semi              1
2    Single              2
3       Row              3
4    Single              2
5 Apartment              4
6 Apartment              4
7       Row              3
Run Code Online (Sandbox Code Playgroud)


gen*_*ama 5

张贴者没有询问是否要查找值exact=FALSE,但我将其添加为我自己和其他人的参考答案。

如果要查找分类值,请使用其他答案。

Excel的vlookup还允许您使用第4个参数(1)近似匹配数字值的匹配match=TRUE。我认为match=TRUE就像在温度计上查找值。默认值为FALSE,非常适合分类值。

如果您想近似匹配(执行查找),则R具有一个名为的函数findInterval(顾名思义),该函数将查找包含连续数字值的间隔/区间。

但是,假设您要findInterval输入多个值。您可以编写循环或使用Apply函数。但是,我发现采用DIY向量化方法更为有效。

假设您有一个由x和y索引的值网格:

grid <- list(x = c(-87.727, -87.723, -87.719, -87.715, -87.711), 
             y = c(41.836, 41.839, 41.843, 41.847, 41.851), 
             z = (matrix(data = c(-3.428, -3.722, -3.061, -2.554, -2.362, 
                                  -3.034, -3.925, -3.639, -3.357, -3.283, 
                                  -0.152, -1.688, -2.765, -3.084, -2.742, 
                                   1.973,  1.193, -0.354, -1.682, -1.803, 
                                   0.998,  2.863,  3.224,  1.541, -0.044), 
                         nrow = 5, ncol = 5)))
Run Code Online (Sandbox Code Playgroud)

并且您想通过x和y查找一些值:

df <- data.frame(x = c(-87.723, -87.712, -87.726, -87.719, -87.722, -87.722), 
                 y = c(41.84, 41.842, 41.844, 41.849, 41.838, 41.842), 
                 id = c("a", "b", "c", "d", "e", "f")
Run Code Online (Sandbox Code Playgroud)

这是可视化的示例:

contour(grid)
points(df$x, df$y, pch=df$id, col="blue", cex=1.2)
Run Code Online (Sandbox Code Playgroud)

等高线图

您可以使用以下类型的公式找到x间隔和y间隔:

xrng <- range(grid$x)
xbins <- length(grid$x) -1
yrng <- range(grid$y)
ybins <- length(grid$y) -1
df$ix <- trunc( (df$x - min(xrng)) / diff(xrng) * (xbins)) + 1
df$iy <- trunc( (df$y - min(yrng)) / diff(yrng) * (ybins)) + 1
Run Code Online (Sandbox Code Playgroud)

您可以更进一步,对z值执行(简单)插值,grid如下所示:

df$z <- with(df, (grid$z[cbind(ix, iy)] + 
                      grid$z[cbind(ix + 1, iy)] +
                      grid$z[cbind(ix, iy + 1)] + 
                      grid$z[cbind(ix + 1, iy + 1)]) / 4)
Run Code Online (Sandbox Code Playgroud)

给您这些值:

contour(grid, xlim = range(c(grid$x, df$x)), ylim = range(c(grid$y, df$y)))
points(df$x, df$y, pch=df$id, col="blue", cex=1.2)
text(df$x + .001, df$y, lab=round(df$z, 2), col="blue", cex=1)
Run Code Online (Sandbox Code Playgroud)

带有值的轮廓图

df
#         x      y id ix iy        z
# 1 -87.723 41.840  a  2  2 -3.00425
# 2 -87.712 41.842  b  4  2 -3.11650
# 3 -87.726 41.844  c  1  3  0.33150
# 4 -87.719 41.849  d  3  4  0.68225
# 6 -87.722 41.838  e  2  1 -3.58675
# 7 -87.722 41.842  f  2  2 -3.00425
Run Code Online (Sandbox Code Playgroud)

注意,ix和iy也可以使用循环找到findInterval,例如,这是第二行的一个示例

findInterval(df$x[2], grid$x)
# 4
findInterval(df$y[2], grid$y)
# 2
Run Code Online (Sandbox Code Playgroud)

匹配ixiydf[2]

脚注:(1)vlookup的第四个参数以前称为“ match”,但是在他们引入功能区之后,它被重命名为“ [range_lookup]”。