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 = ",")
搜索了一段时间后,我还没有找到一个优雅的解决方案(通常像 "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 = ",")