在函数接受多个不同列的参数时使用dplyr mutate_
我有一个在函数接受多个不同列的参数时使用dplyr mutate_,r,dplyr,R,Dplyr,我有一个data.frame,其中有大量列的名称遵循一种模式。例如: df <- data.frame( x_1 = c(1, NA, 3), x_2 = c(1, 2, 4), y_1 = c(NA, 2, 1), y_2 = c(5, 6, 7) ) 有没有一种方法可以让mutate\u在/mutate\u每个 这: 我尝试过的各种变体都失败了 问题与类似,但不同之处在于函数调用的第二个参数不是单个列,而是vars中每列的不同列 提前谢谢 我不知道你是否可以这样
data.frame
,其中有大量列的名称遵循一种模式。例如:
df <- data.frame(
x_1 = c(1, NA, 3),
x_2 = c(1, 2, 4),
y_1 = c(NA, 2, 1),
y_2 = c(5, 6, 7)
)
有没有一种方法可以让mutate\u在
/mutate\u每个
这:
我尝试过的各种变体都失败了
问题与类似,但不同之处在于函数调用的第二个参数不是单个列,而是vars中每列的不同列
提前谢谢 我不知道你是否可以这样理解,但对于这个问题,这里有一个不同的观点。如果您发现自己拥有非常广泛的数据(例如,大量具有类似名称的列),并且希望对其进行处理,那么使用
tidyr::gather
(请参见此处的文档)整理数据(长期的stata
术语)可能会有所帮助
将数据转换为这种格式后,使用
groupby
组合和重新排列值会更容易,而不是尝试在事物上进行变异。例如,您可以使用df%%>%gather()%%>%mutate(var=substr(key,1,1))
对第一个值进行ge,并使用groupby(var)
对x和y进行不同的操作。当我问这个问题时,答案是“你不能!”这不再是答案,由于tidyr
现在支持pivot\u更宽
和pivot\u更长
这是一个老问题,但我同意Jesse的观点,您需要稍微整理一下数据collect
将是一种方法,但它缺少了某种可能性,即stats::restrape
可以指定要收集的列组。下面是一个使用重塑的解决方案:
df %>%
reshape(varying = list(c("x_1", "y_1"), c("x_2", "y_2")),
times = c("x", "y"),
direction = "long") %>%
mutate(x = ifelse(is.na(x_1), x_2, x_1)) %>%
reshape(idvar = "id",
timevar = "time",
direction = "wide") %>%
rename_all(funs(gsub("[a-zA-Z]+(_*)([0-9]*)\\.([a-zA-Z]+)", "\\3\\1\\2", .)))
# id x_1 x_2 x y_1 y_2 y
# 1 1 1 1 1 NA 5 5
# 2 2 NA 2 2 2 6 2
# 3 3 3 4 3 1 7 1
为了对任意数量的列对执行此操作,您可以执行以下操作:
df2 <- setNames(cbind(df, df), c(t(outer(letters[23:26], 1:2, paste, sep = "_"))))
v <- split(names(df2), purrr::map_chr(names(df2), ~ gsub(".*_(.*)", "\\1", .)))
n <- unique(purrr::map_chr(names(df2), ~ gsub("_[0-9]+", "", .) ))
df2 %>%
reshape(varying = v,
times = n,
direction = "long") %>%
mutate(x = ifelse(is.na(!!sym(v[[1]][1])), !!sym(v[[2]][1]), !!sym(v[[1]][1]))) %>%
reshape(idvar = "id",
timevar = "time",
direction = "wide") %>%
rename_all(funs(gsub("[a-zA-Z]+(_*)([0-9]*)\\.([a-zA-Z]+)", "\\3\\1\\2", .)))
# id w_1 w_2 w x_1 x_2 x y_1 y_2 y z_1 z_2 z
# 1 1 1 1 1 NA 5 5 1 1 1 NA 5 5
# 2 2 NA 2 2 2 6 2 NA 2 2 2 6 2
# 3 3 3 4 3 1 7 1 3 4 3 1 7 1
df2%
重塑(idvar=“id”,
timevar=“time”,
direction=“wide”)%%>%
重命名所有(funs(gsub(“[a-zA-Z]+([0-9]*)\ \。([a-zA-Z]+)”,“\\3\\1\\2”,))
#id w_1 w_2 w x_1 x_2 x y_1 y_2 y z_1 z_2 z
#111NA55111NA555
#2 2钠2 2 6 2钠2 2 6 2
# 3 3 3 4 3 1 7 1 3 4 3 1 7 1
这假设应该进行比较的列彼此相邻,并且可能具有NA值的所有列都位于以\u 1
为后缀的列中,替换值列以\u 2
为后缀,我认为这会产生相反的效果。在收集
”之后,我会遇到根据密钥前缀和原始行的唯一标识符进行分组的问题。为了详细说明这个问题,我的data.frame
包含了大约117个不同项目的数据,这些项目是由不同实验室分批测试样本的实验室测试结果。因此,每个项目有7列——为样本测量的值、采样值的范围以及有关批次的各种数据,包括批次差异和校准信息。因此,需要进行一些相当实质性的处理才能使值规范化和一致。总共是7列还是117列?您拥有的列越多(列操作也越复杂),就越难让mutate
系列执行您喜欢的操作。您可能希望使其更整洁(例如,请参见),并使用groupby
,该工具旨在处理此类问题。或者您可以切换到基本R操作(这可能更容易处理复杂的列操作)。117个测量变量各7列。使用每个测量变量的其他6列,将原始测量值转换为可用测量值的过程对于117个变量中的每一个都是相同的。这就是为什么我在寻找一种基于mutate\uu
函数族的方法。到目前为止,我能想到的是创建7个矩阵,每个矩阵有117列,但这是一个非常不幸的方法,它确实使代码复杂化。我现在正在处理类似的事情。这与我上一个问题中的问题相同:,但在这种情况下,数据集太大,导致RStudio崩溃。data.table
set
循环可能是更快的方法之一dplyr::coalesce
在可读性方面可能会更好一些,我认为这是正确的,谢谢。我同意数据需要整理——这个操作是一系列步骤中的早期操作,这些步骤的目的是整理数据。
> df %>% gather()
key value
1 x_1 1
2 x_1 NA
3 x_1 3
4 x_2 1
5 x_2 2
6 x_2 4
7 y_1 NA
8 y_1 2
9 y_1 1
10 y_2 5
11 y_2 6
12 y_2 7
df %>%
reshape(varying = list(c("x_1", "y_1"), c("x_2", "y_2")),
times = c("x", "y"),
direction = "long") %>%
mutate(x = ifelse(is.na(x_1), x_2, x_1)) %>%
reshape(idvar = "id",
timevar = "time",
direction = "wide") %>%
rename_all(funs(gsub("[a-zA-Z]+(_*)([0-9]*)\\.([a-zA-Z]+)", "\\3\\1\\2", .)))
# id x_1 x_2 x y_1 y_2 y
# 1 1 1 1 1 NA 5 5
# 2 2 NA 2 2 2 6 2
# 3 3 3 4 3 1 7 1
df2 <- setNames(cbind(df, df), c(t(outer(letters[23:26], 1:2, paste, sep = "_"))))
v <- split(names(df2), purrr::map_chr(names(df2), ~ gsub(".*_(.*)", "\\1", .)))
n <- unique(purrr::map_chr(names(df2), ~ gsub("_[0-9]+", "", .) ))
df2 %>%
reshape(varying = v,
times = n,
direction = "long") %>%
mutate(x = ifelse(is.na(!!sym(v[[1]][1])), !!sym(v[[2]][1]), !!sym(v[[1]][1]))) %>%
reshape(idvar = "id",
timevar = "time",
direction = "wide") %>%
rename_all(funs(gsub("[a-zA-Z]+(_*)([0-9]*)\\.([a-zA-Z]+)", "\\3\\1\\2", .)))
# id w_1 w_2 w x_1 x_2 x y_1 y_2 y z_1 z_2 z
# 1 1 1 1 1 NA 5 5 1 1 1 NA 5 5
# 2 2 NA 2 2 2 6 2 NA 2 2 2 6 2
# 3 3 3 4 3 1 7 1 3 4 3 1 7 1