R 使用mutate_at在每列之后插入相对值(相对于TIBLE的第二列)
我有一个包含多个列的dataframe tibble,对于前两列之后的每一列,我希望保留绝对值,但也插入相对于第二列的值。 例如,我从以下数据框开始—列名可能会有所不同!:R 使用mutate_at在每列之后插入相对值(相对于TIBLE的第二列),r,dplyr,mutate,tibble,R,Dplyr,Mutate,Tibble,我有一个包含多个列的dataframe tibble,对于前两列之后的每一列,我希望保留绝对值,但也插入相对于第二列的值。 例如,我从以下数据框开始—列名可能会有所不同!: df = tibble(val1 = 5:10, val2 = 10:15, val3 = 15:20); df # A tibble: 6 x 3 val1 val2 val3 <int> <int> <int> 1 5 10 15 2 6
df = tibble(val1 = 5:10, val2 = 10:15, val3 = 15:20); df
# A tibble: 6 x 3
val1 val2 val3
<int> <int> <int>
1 5 10 15
2 6 11 16
3 7 12 17
4 8 13 18
5 9 14 19
6 10 15 20
不幸的是,我无法在调用时编写适当的mutate_,以便在每个值列之后插入该相对列。事实上,我无法使用funs编写一个mutate_,它通过按位置而不是名称访问其他列来修改列
用相对值替换val2和val3使用lambda函数而不是funs工作,但不会根据需要保留原始val2和val3列:
df %>%
mutate_at(vars(-1), function(v) v/.[[1]])
# A tibble: 6 x 3
val1 val2 val3
<int> <dbl> <dbl>
1 5 2.00 3.00
2 6 1.83 2.67
3 7 1.71 2.43
4 8 1.62 2.25
5 9 1.56 2.11
6 10 1.50 2.00
与之相比的一个复杂之处是,我的val1列没有固定的名称,即它并不总是被称为val1,因此我不能在funs参数中按名称使用它。另一个复杂的问题是,tibble是使用大量管道操作符动态创建的,通常不存储在变量中,因此我不能简单地用df[[1]]除以
那么,dplyr插入相对列(即每列后面第一列的百分比)的正确方法是什么呢?通过将函数包装到列表中来为其命名,这样mutate\u将创建新的列。以下列名称可能不太理想,因此如果需要,您可能需要重命名它们:
在Psidom的帮助下,这是我对该问题的最终解决方案:
interleaveColumns = function(v) {
c(1, unlist(split(2:length(v), 1:((length(v)-1)/2)), use.names = FALSE))
}
df = tibble(val1 = 5:10, val2 = 10:15, val3 = 15:20, val4 = 25:30, val5 = 1:6);
# mutate_at can be given a named list to create a new column
# for each existing columnt (appended to the end => we need
# to reorder the columns and interleave the new columns with
# the old columns using the interleaveColumns function)
df %>%
mutate_at(vars(-1), list(rel = function(v) v/.[[1]])) %>%
select(interleaveColumns(.))
# A tibble: 6 x 9
val1 val2 val2_rel val3 val3_rel val4 val4_rel val5 val5_rel
<int> <int> <dbl> <int> <dbl> <int> <dbl> <int> <dbl>
1 5 10 2.00 15 3.00 25 5.00 1 0.200
2 6 11 1.83 16 2.67 26 4.33 2 0.333
3 7 12 1.71 17 2.43 27 3.86 3 0.429
4 8 13 1.62 18 2.25 28 3.50 4 0.500
5 9 14 1.56 19 2.11 29 3.22 5 0.556
6 10 15 1.50 20 2.00 30 3.00 6 0.600
谢谢,在列表中加后缀是我从来没有想到过的。命名不是问题,因为无论如何我都会在kable中对col.names进行后期处理。不幸的是,您的解决方案将所有相关列追加到末尾。有没有办法在每个值列后面插入新列?列的数量不是固定的,因为它们是来自不同死亡率表的值,我需要为一个发布报告这些值,所以手动重新排列并不简单。如何对列名进行排序?链%>%selectsortnames。在变异之后?这可能不会保留原始列的顺序,但会将rel列附加到相应的val列之后。或者,如果要保持所有列的顺序,可以执行以下操作:选择1,{mut_cols=tailnames.,-1;cbindmut_cols[cT,F],mut_cols[cF,T]}谢谢,现在我自己找到了一种方法,使用一个helper函数来重新排序列以生成索引:interleaveColumns=functionv{c1,unlistsplit2:lengthv,1:lengthv-1/2,use.names=FALSE}然后一个简单的选择将执行%>%selectinterleaveColumns。
df %>%
mutate_at(vars(-1), funs(./.tbl[[1]]))
Error in mutate_impl(.data, dots) :
Evaluation error: object '.tbl' not found.
df %>%
mutate_at(vars(-1), funs(function(v) v/.[[1]]))
Error in mutate_impl(.data, dots) :
Column `val2` is of unsupported type function
df %>% mutate_at(vars(-1), list(rel = function(v) v / .[[1]]))
# A tibble: 6 x 5
# val1 val2 val3 val2_rel val3_rel
# <int> <int> <int> <dbl> <dbl>
#1 5 10 15 2.00 3.00
#2 6 11 16 1.83 2.67
#3 7 12 17 1.71 2.43
#4 8 13 18 1.62 2.25
#5 9 14 19 1.56 2.11
#6 10 15 20 1.50 2.00
interleaveColumns = function(v) {
c(1, unlist(split(2:length(v), 1:((length(v)-1)/2)), use.names = FALSE))
}
df = tibble(val1 = 5:10, val2 = 10:15, val3 = 15:20, val4 = 25:30, val5 = 1:6);
# mutate_at can be given a named list to create a new column
# for each existing columnt (appended to the end => we need
# to reorder the columns and interleave the new columns with
# the old columns using the interleaveColumns function)
df %>%
mutate_at(vars(-1), list(rel = function(v) v/.[[1]])) %>%
select(interleaveColumns(.))
# A tibble: 6 x 9
val1 val2 val2_rel val3 val3_rel val4 val4_rel val5 val5_rel
<int> <int> <dbl> <int> <dbl> <int> <dbl> <int> <dbl>
1 5 10 2.00 15 3.00 25 5.00 1 0.200
2 6 11 1.83 16 2.67 26 4.33 2 0.333
3 7 12 1.71 17 2.43 27 3.86 3 0.429
4 8 13 1.62 18 2.25 28 3.50 4 0.500
5 9 14 1.56 19 2.11 29 3.22 5 0.556
6 10 15 1.50 20 2.00 30 3.00 6 0.600