R for 循环中的两个控制变量(优雅地)

Two Control Variables in R for loop (elegantly)

搜索了一段时间后,我还没有找到一个优雅的解决方案(通常像 "just vectorize it" 这样迂腐的答案可能并不总是适用),所以我想问一下。

简单的问题是这样的: 我需要遍历 2 个控制变量。 (这是通常被问到的,并简短地回答)

我遇到的真正(特定)问题可能并不适用于所有人(寻找此类问题的答案)是这样的: 我有一个数据框。可以说是工资单数据。

ID,FIRST_NAME,LAST_NAME,PAYDATE,AMT
912367,Jim,Smith,1/1/2000,5000
1102467,LAURA,JAMES,1/1/2000,5000
812367,DAVID,johnson,1/1/2000,5000
555555,ian,Smith,1/1/2000,5000
912367,Jim,SMITH,1/8/2000,4000
...

是的,名字就是这么脏。 Say Unnamed Boss 走过来说,用这个和其他数据做一些事情……然后给你一个名字列表。当然,它们的格式正确:

Smith,Jim R
Fields,Samantha
Smith,Kelly
Lensdotter,Patricia

我选择打破它们(在 csv 中很容易)以类似于

的方式读取它们
fnames <- c(Jim,Samantha,Kelly,Patricia)

和关联的姓氏(即 2 个变量)。然后我读入数据框,做了一些嵌套循环和 greps(忽略大小写)。搜索了更简单的方法并找到了如何 "python zip" 列表等,但我想知道是否有更简单的方法?

我的代码非常类似于:

EID <- vector(mode="integer")
for (i in 1:length(lnames)){
  l <- lnames[i]
  f <- fnames[i]
  if(grepl(l,payroll[3],ignore.case = T)){
    paycut1 <- payroll[grepl(l,payroll$LAST_NAME,ignore.case = T),]
    if(grepl(f,paycut[2],ignore.case=T)){
      paycut2 <- paycut[grepl(f,paycut$FIRST_NAME,ignore.case=T),]
    }
    print(paste0(l,", ",f," Has EID: ", paycut2[1,1]))
    EIDs <- c(EIDs,paycut2[1,1])
  }else{
    print(paste0(l,", ",f," NOT in Payroll Data: "))
  }
}

这样我就可以从与名称关联的文件中获取 ID(这样我就不必处理名称了!)。有什么建议么? (我不想使用 for (i in range): 构造(有点不雅),而不是更像 for i,j: 构造的 c/python。

(开头的解释不好意思,但是我觉得搜索这样的问题就应该得到答案,并不是每个人都能正确地提出问题,所以像"just vectorize it"这样的回答可能不适用于他们的情况阻止了他们继续询问)

P.S。如果我以完全错误的方式去做,我并不反对其他观点。我来自 C 背景,所以我习惯于循环和非矢量化代码。我只是看不出如何对此进行矢量化。欢迎批评,虽然只是有益的批评。

只需对其进行矢量化!

更严重的是,您的代码看起来并不像 R 代码 - 如果可以的话,您真的不想嵌套循环。

以下是我的处理方法。

首先我们清理名称:

payroll$FIRST_NAME <- toupper(payroll$FIRST_NAME)
payroll$LAST_NAME <- toupper(payroll$LAST_NAME)
names$V2 <- toupper(sub(" .*", "", names$V2))
names$V1 <- toupper(names$V1)

然后我们可以使用 inner_join:

得到匹配的那些
library(dplyr)
inner_join(names, payroll, by = c(V2 = "FIRST_NAME", V1 = "LAST_NAME"))

     V1  V2     ID  PAYDATE  AMT
1 SMITH JIM 912367 1/1/2000 5000
2 SMITH JIM 912367 1/8/2000 4000

和那些不匹配的,使用 anti_join:

anti_join(names, payroll, by = c(V2 = "FIRST_NAME", V1 = "LAST_NAME"))
          V1       V2
1      SMITH    KELLY
2 LENSDOTTER PATRICIA
3     FIELDS SAMANTHA

以下是我获取数据的方式:

payroll <- read.table(text = "ID,FIRST_NAME,LAST_NAME,PAYDATE,AMT
912367,Jim,Smith,1/1/2000,5000
1102467,LAURA,JAMES,1/1/2000,5000
812367,DAVID,johnson,1/1/2000,5000
555555,ian,Smith,1/1/2000,5000
912367,Jim,SMITH,1/8/2000,4000", header=TRUE, sep = ",")


names <- read.table(text="Smith,Jim R
Fields,Samantha
Smith,Kelly
Lensdotter,Patricia", header=FALSE, sep = ",")