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

时间:2015-11-11 17:58:52

标签: r control-flow

经过一段时间的搜索,我找不到一个优雅的解决方案(通常是迂腐的答案,比如"只是对它进行矢量化"这可能不会一直适用),所以我想我是&#39 ;问。

简单的问题是: 我需要循环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
...

是的,这些名字很脏。说未命名的老板出现并说,用这个和其他数据做一些事情......然后给你一个名单。当然,他们的格式正确:

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

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

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

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

我的代码非常类似于:

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。

(对不起开头的解释,但我认为搜索这样的问题值得回答,并不是每个人都可以正确构建一个问题,所以答案就像&#34;只是向量化它&#34;这可能是在他们的情况下不适用于阻止他们继续询问)

P.S。如果我以完全错误的方式解决这个问题,我并不反对其他观点。我来自C背景,因此我习惯于循环和非矢量化代码。我只是无法看到如何对此进行矢量化。批评,虽然只是有用的批评,但欢迎。

1 个答案:

答案 0 :(得分:1)

只是矢量化它!

更严重的是,您的代码看起来并不像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 = ",")