我想创建一个函数来将值映射到组和不同的变量。
df <- data.frame(x = c("a", "a", "b", "c", "c", "d", "e"),
y = c(1, 5, 5, 1, 6, 8, 3),
z = runif(7),
stringsAsFactors = FALSE)
例如对于这些数据,对于变量x,我想将值“a”,“b”映射到“label1”,将“c”“d”“e”映射到“label2”,并将变量y映射到将1,3映射为“code1”,将5,6,8映射为“code2”。
groups <- list(x = list(label1 = c("a", "b"), label2 = c("c", "d", "e")),
y = list(code1 = c(1, 3), code2 = c(5, 6, 8)))
在这个例子中,我想要映射来自2个变量的值,但它可以是1,3,4 ......所以我不想为每个变量创建数据帧查找或逐个分配每个变量。这就是为什么我使用一个列表(我在函数参数中发现它更友好)并且不能使用$。 +这是在函数内部使用的,所以我不需要任何硬编码。
所以实际上我创建了这个函数:
f <- function(x, groups) {
table <- reshape2::melt(groups)
table <- split(table, table$L1)
for (i in seq_along(table)) {
x[names(table)[i]] <- table[[i]]$L2[match(x[,names(table)[i]], table[[i]]$value)]
}
return(x)
}
这是我尝试使用嵌套列表获得“友好”群组参数的最佳方法。
我尝试了类似dplyr::mutate
的语法,例如myFunction(x = list(label1 = c("a", "b"), label2 = c("c", "d", "e")), y = list(code1 = c(1, 3), code2 = c(5, 6, 8)))
这可能非常好,但这只是一个有很多参数的更大函数的一部分所以我认为这不可行(至少我没有成功)。
但我确信有更好的方法可以做到这一点,或者可能已经存在功能。 你有改进的想法吗?谢谢!
答案 0 :(得分:6)
您可以使用Grid
尝试使用data.frames作为对应关系:
match
编辑考虑到“新”问题的限制,您可以执行此操作,保持# define the correspondences
df2 <- data.frame(v1=letters[1:5], v2=paste0("label", c(1,1,2,2,2)), stringsAsFactors=F)
df3 <- data.frame(v1=c(1, 3, 5, 6, 8), v2=paste0("code", c(1,1,2,2,2)), stringsAsFactors=F)
# change your variables
df$x <- df2$v2[match(df$x, df2$v1)]
df$y <- df3$v2[match(df$y, df3$v1)]
和df
不变:
groups
答案 1 :(得分:2)
这种方法与@ MarkeD一样,将编码放在新列中:
library(data.table)
setDT(df)
mymaps <- lapply(groups, stack)
for (nm in names(mymaps)){
setkeyv(df,nm)
df[mymaps[[nm]], paste0(nm,"_new") := ind]
}
要覆盖变量,您可以添加df[,(nm):=NULL]
和setnames(df,paste0(nm,"_new"),nm)
。
答案 2 :(得分:1)
这个怎么样 - 根据需要制作一个命名查找列表:
groups <- list(a = 'label1', b='label1', c='label2',d='label2',e='label2',
'1'='code1', '3' = 'code1', '5' = 'code2','6' = 'code2','7' = 'code2' )
小心使用数字作为名称,因为它将默认为位置。
然后你可以使用子集来获得你的比赛:
## generate the data frame example:
df <- data.frame(x = c("a", "a", "b", "c", "c", "d", "e"),
y = c(1, 5, 5, 1, 6, 8, 3),
z = runif(7),
stringsAsFactors = FALSE)
df$group_x <- groups[df$x]
## using as.character to avoid numbers throwing off the lookup
df$group_y <- groups[as.character(df$y)]
创建:
x y z group_x group_y
a 1 0.1684421 label1 code1
a 5 0.7459545 label1 code2
b 5 0.5308211 label1 code2
c 1 0.6637787 label2 code1
c 6 0.3493355 label2 code2
d 8 0.8303369 label2 code2
e 3 0.8727316 label2 code1
答案 3 :(得分:1)
或者:
df[,'x'] <- ifelse(df[,'x'] %in% c('a', 'b'), 'label1', 'label2')
df[,'y'] <- ifelse(df[,'y'] %in% c(1,3), 'code1', 'code2')
# x y z
# 1 label1 code1 0.4536355
# 2 label1 code2 0.2827496
# 3 label1 code2 0.8643375
# 4 label2 code1 0.9481302
# 5 label2 code2 0.8662686
# 6 label2 code2 0.4208953
# 7 label2 code1 0.4438536