我有一个包含emp_id
和job_code
的简单表格。我想根据payout
job_code
我已经使用嵌套的ifelse来管理这个问题,但如果我有更多job_code
'
library(dplyr)
set.seed(1)
emp_id <- round(rnorm(100, 500000, 10000))
job_code <- sample(c('a', 'b', 'c'), 100, replace = TRUE)
result <- sample(c(1,2,3,4), 100, replace = TRUE)
df <- data.frame(emp_id = emp_id, job_code = job_code, result = result)
job_a <- c(0, 500, 1000, 5000)
job_b <- c(0, 200, 500, 750)
job_c <- c(0, 250, 750, 1000)
# Works but sucky
df %>% mutate(payout = ifelse(job_code == 'a', job_a[result],
ifelse(job_code == 'b', job_b[result],
job_c[result])))
如果您愿意,请和dput
:
structure(list(emp_id = c(493735, 501836, 491644, 515953, 503295,
491795, 504874, 507383, 505758, 496946, 515118, 503898, 493788,
477853, 511249, 499551, 499838, 509438, 508212, 505939, 509190,
507821, 500746, 480106, 506198, 499439, 498442, 485292, 495218,
504179, 513587, 498972, 503877, 499462, 486229, 495850, 496057,
499407, 511000, 507632, 498355, 497466, 506970, 505567, 493112,
492925, 503646, 507685, 498877, 508811, 503981, 493880, 503411,
488706, 514330, 519804, 496328, 489559, 505697, 498649, 524016,
499608, 506897, 500280, 492567, 501888, 481950, 514656, 501533,
521726, 504755, 492901, 506107, 490659, 487464, 502914, 495567,
500011, 500743, 494105, 494313, 498648, 511781, 484764, 505939,
503330, 510631, 496958, 503700, 502671, 494575, 512079, 511604,
507002, 515868, 505585, 487234, 494267, 487754, 495266), job_code = structure(c(1L,
1L, 2L, 1L, 1L, 2L, 2L, 1L, 1L, 3L, 3L, 1L, 3L, 3L, 3L, 1L, 2L,
3L, 3L, 2L, 1L, 1L, 1L, 2L, 3L, 2L, 1L, 1L, 2L, 3L, 2L, 1L, 2L,
2L, 2L, 3L, 3L, 2L, 2L, 2L, 1L, 2L, 3L, 1L, 2L, 1L, 2L, 1L, 2L,
3L, 3L, 3L, 2L, 2L, 2L, 1L, 1L, 2L, 2L, 3L, 2L, 1L, 1L, 3L, 3L,
1L, 1L, 3L, 2L, 1L, 1L, 1L, 2L, 1L, 1L, 1L, 1L, 1L, 2L, 3L, 1L,
2L, 3L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 3L, 1L, 2L, 3L, 1L,
1L, 1L, 3L), .Label = c("a", "b", "c"), class = "factor"), result = c(3,
1, 2, 2, 2, 4, 1, 4, 1, 2, 1, 1, 4, 3, 2, 2, 1, 2, 4, 3, 3, 2,
2, 4, 4, 4, 4, 4, 2, 4, 4, 2, 2, 4, 1, 2, 2, 1, 3, 4, 4, 1, 3,
2, 3, 2, 2, 1, 2, 3, 2, 1, 4, 2, 4, 2, 4, 1, 4, 2, 1, 2, 4, 2,
3, 4, 1, 3, 3, 2, 2, 3, 4, 1, 1, 2, 2, 4, 1, 2, 2, 3, 3, 4, 1,
1, 4, 4, 1, 4, 1, 1, 4, 3, 1, 2, 3, 2, 2, 1)), .Names = c("emp_id",
"job_code", "result"), row.names = c(NA, -100L), class = "data.frame")
我最理想的做法是在data.frame中获得付款,但不确定如何正确引用它:
job_payouts <- data.frame(a = job_a, b = job_b, c = job_c)
# Won't work...
df %>% mutate(payout = job_payouts$job_code[result])
答案 0 :(得分:10)
这可以通过基础R中的超酷矩阵索引方法来实现,这种方法非常快速有效。
# build jobs payout lookup matrix, by hand (see edit below for an extension)
jobs <- rbind(job_a, job_b, job_c)
# add row names to the matrix for convenient reference
rownames(jobs) <- levels(df$job_code)
# get payout using matrix indexing
df$payout <- jobs[cbind(df$job_code, df$result)]
返回
# print out first 6 observations
head(df)
emp_id job_code result payout
1 493735 a 3 1000
2 501836 a 1 0
3 491644 b 2 200
4 515953 a 2 500
5 503295 a 2 500
6 491795 b 4 750
# print out jobs matrix for comparison
jobs
[,1] [,2] [,3] [,4]
a 0 500 1000 5000
b 0 200 500 750
c 0 250 750 1000
有一些值得一提的细节。
data.frame
函数转换job_code字符向量,因此df$job_code
是一个因子变量,其中标签与自然数1,2,3,...相关联。默认情况下, factor按字母顺序按标签排序,因此,在此示例中,标签“a”对应于1,“b”对应于2,“c”对应3.您可以使用levels
函数查找顺序因子变量并在该模板之后构建作业矩阵。cbind(df$job_code, df$result)
形成一个2 nrow(df)
(100)矩阵,用于使用矩阵索引从作业矩阵中查找每个员工的nrow(df)
支付值。 R intro manual在矩阵索引方面有一个很好的介绍部分,其他详细信息可以在help("[")
中找到。修改 自动构建查找矩阵
在对这个答案的评论中,OP表示担心手工构建查找矩阵(我称之为“作业”)将是乏味的并且容易出错。为了解决这些有效的问题,我们可以对mget
函数使用一个有点模糊的参数,“ifnotfound”。这个参数允许我们控制mget
在名称向量中出现但在环境中不存在时返回的列表元素的输出。
在评论中,我建议使用NA
填写下面评论中的缺失级别。我们可以使用NA
作为“ifnotfound。”的输入来扩展它。
假设df$job_code
是按此顺序具有“a”,“aa”,“b”和“c”级别的因子。然后我们按如下方式构建查找矩阵:
# build vector for example, the actual code, using levels(), follows as a comment
job_codes <- c("a", "aa", "b", "c") # job_codes <- levels(df$jobcodes)
# get ordered list of payouts, with NA for missing payouts
payoutList <- mget(paste0("job_", job_codes), ifnotfound=NA)
返回一个命名列表。
payoutList
$job_a
[1] 0 500 1000 5000
$job_aa
[1] NA
$job_b
[1] 0 200 500 750
$job_c
[1] 0 250 750 1000
请注意,payoutList$job_aa
是一个NA。现在,从此列表中构建矩阵。
# build lookup matrix using do.call() and rbind()
jobs.lookupMat <- do.call(rbind, payoutList)
jobs.lookupMat
[,1] [,2] [,3] [,4]
job_a 0 500 1000 5000
job_aa NA NA NA NA
job_b 0 200 500 750
job_c 0 250 750 1000
矩阵的行根据因子df$job_code
的级别进行了正确排序,方便地命名,NA
在任何没有支付的地方填充行。
答案 1 :(得分:3)
不改变数据结构,可以通过定义函数来实现:
job_search <- function(code){
var_name <- paste0("job_",code)
if (exists(var_name)){
return(get(var_name))
}else{
return(NA)
}
}
library(data.table)
setDT(df)
df[, payout := job_search(job_code)[result], by = .(emp_id)]
df
emp_id job_code result payout
1: 493735 a 3 1000
2: 501836 a 1 0
3: 491644 b 2 200
4: 515953 a 2 500
5: 503295 a 2 500
6: 491795 b 4 750
7: 504874 b 1 0
8: 507383 a 4 5000
9: 505758 a 1 0
10: 496946 c 2 250
11: 515118 c 1 0
12: 503898 a 1 0
...
但是,这是保存数据的一种相当不稳定的方法,而且粘贴+获取语法是错综复杂的。
存储数据的更好方法是查找表:
library(data.table)
job_a <- data.frame(payout = c(0, 500, 1000, 5000))
job_b <- data.frame(payout = c(0, 200, 500, 750))
job_c <- data.frame(payout = c(0, 250, 750, 1000))
job_lookup <- rbindlist( #this is a data.table
l = list(a = job_a,b = job_b,c = job_c),
idcol = TRUE
)
# create your result index
job_lookup[, result := 1:.N, by = .id]
job_lookup
.id payout result
1: a 0 1
2: a 500 2
3: a 1000 3
4: a 5000 4
5: b 0 1
6: b 200 2
7: b 500 3
8: b 750 4
9: c 0 1
10: c 250 2
11: c 750 3
12: c 1000 4
# merge to your initial data.frame
merge(df, job_lookup, by.x = c("job_code","result"), by.y = c(".id","result"), all.x = TRUE)
job_code result emp_id payout
1 a 1 505758 0
2 a 1 501836 0
3 a 1 503898 0
4 a 1 494575 0
5 a 1 487464 0
6 a 1 503700 0
7 a 1 505939 0
8 a 1 503330 0
9 a 1 512079 0
10 a 1 481950 0
11 a 1 507685 0
12 a 1 490659 0
...
答案 2 :(得分:3)
使用 tidyverse 中的工具:
library(dplyr)
library(stringr)
library(tidyr)
# your data
set.seed(1)
emp_id <- round(rnorm(100, 500000, 10000))
job_code <- sample(c('a', 'b', 'c'), 100, replace = TRUE)
result <- sample(c(1,2,3,4), 100, replace = TRUE)
# construct a data frame
df <-
data.frame(emp_id = emp_id,
job_code = job_code,
result = result,
stringsAsFactors = FALSE)
# your jobs
job_a <- c(0, 500, 1000, 5000)
job_b <- c(0, 200, 500, 750)
job_c <- c(0, 250, 750, 1000)
# construct a data frame
my_job <-
data.frame(job_a, job_b, job_c) %>%
gather(job, value) %>%
group_by(job) %>%
mutate(result = 1:n(),
job_code = str_replace(job, "job_", "")) %>%
ungroup %>%
select(-job)
# join df and my_job into my_results table
my_results <-
left_join(df, my_job)
<强>结果:
my_results %>% tbl_df
Source: local data frame [100 x 4]
emp_id job_code result value
(dbl) (chr) (dbl) (dbl)
1 493735 a 3 1000
2 501836 a 1 0
3 491644 b 2 200
4 515953 a 2 500
5 503295 a 2 500
6 491795 b 4 750
7 504874 b 1 0
8 507383 a 4 5000
9 505758 a 1 0
10 496946 c 2 250
.. ... ... ... ...