例如,我感兴趣的是将data.frame
或tibble
的所有列(几乎)替换为从每行中减去行最小值的列。例如,如果X
是一个数值矩阵,那么在基数R中,我会写:
X = sweep(X, 1, apply(X, 1, min))
我当前使用我拥有的数据执行此操作的功能-我将立即解释格式-将数值列拉出到矩阵中,进行扫描,然后cbind
将转换后的数据和非数值数据又重新组合在一起。那就是:
subtractMin = function(data){
X = data %>%
select(starts_with("X")) %>%
as.matrix()
X = sweep(X, 1, apply(X, 1, min))
labels = data %>%
select(-starts_with("X"))
return(cbind(labels, X))
}
这让我感到效率低下,并且必须是一种更明智的方法。
我认为了解给定的上下文并不重要,但是我的数据有77行和1133列。其中四列包含标签信息,其余1129列包含每个观测值的数值测量值(如果您愿意的话,它们是光谱)。数字变量的数量使得单个mutate
不再可行。同样,您仍然需要知道最小行数才能对每一行进行标准化。
已要求我添加一些数据。原始数据有1000列以上,因此我将提供一个较小的数据集
> x.df
nm X1799.38928 X1798.01526 X1796.64124 source color rep
1 s001c1 13901.944 13889.056 13883.334 01 c 1
2 s001c2 17293.586 17279.375 17291.365 01 c 2
3 s001c3 8011.764 8028.584 8033.548 01 c 3
4 s001c4 7499.272 7510.719 7517.064 01 c 4
5 s001c5 20300.408 20293.604 20297.185 01 c 5
答案 0 :(得分:3)
(就其价值而言,我认为此处的否决票有些刺耳,没有根据。问题陈述很明确,示例数据已包含在编辑中。)
通过将数字列中的数据从宽转换为长(使用gather
,按行分组(使用group_by
),减去最小值(使用{{1 }}),然后从长到宽转换(使用mutate
)。
spread
library(tidyverse)
df %>%
gather(k, v, starts_with("X")) %>%
group_by(nm) %>%
mutate(v = v - min(v)) %>%
spread(k, v) %>%
select(names(df))
## A tibble: 5 x 7
## Groups: nm [5]
# nm X1799.38928 X1798.01526 X1796.64124 source color rep
# <fct> <dbl> <dbl> <dbl> <int> <fct> <int>
#1 s001c1 18.6 5.72 0. 1 c 1
#2 s001c2 14.2 0. 12.0 1 c 2
#3 s001c3 0. 16.8 21.8 1 c 3
#4 s001c4 0. 11.4 17.8 1 c 4
#5 s001c5 6.80 0. 3.58 1 c 5
答案 1 :(得分:3)
我知道您要tidyverse
/ dplyr
,但如果您忽略了基数R,可以采用以下解决方案:
ind <- !names(df) %in% c("nm","source","color","rep")
df[ind] <- df[ind] - do.call(pmin, df[ind])
df
# nm X1799.38928 X1798.01526 X1796.64124 source color rep
# 1 s001c1 18.610 5.722 0.000 1 c 1
# 2 s001c2 14.211 0.000 11.990 1 c 2
# 3 s001c3 0.000 16.820 21.784 1 c 3
# 4 s001c4 0.000 11.447 17.792 1 c 4
# 5 s001c5 6.804 0.000 3.581 1 c 5
我想这将成为tidyverse
解决方案(尽管不是很惯用):
df %>%
split.default(!names(df) %in% c("nm","source","color","rep")) %>%
map_at("TRUE", ~ .x - invoke(pmin,.x)) %>%
bind_cols
# nm source color rep X1799.38928 X1798.01526 X1796.64124
# 1 s001c1 1 c 1 18.610 5.722 0.000
# 2 s001c2 1 c 2 14.211 0.000 11.990
# 3 s001c3 1 c 3 0.000 16.820 21.784
# 4 s001c4 1 c 4 0.000 11.447 17.792
# 5 s001c5 1 c 5 6.804 0.000 3.581
答案 2 :(得分:2)
我们可以使用pmin
来获取行的最小值,然后使用mutate_at
来查找列和最小值之间的差异
library(tidyverse)
ins <- x.df %>%
select(starts_with("X")) %>%
reduce(pmin)
x.df %>%
mutate_at(vars(starts_with("X")), funs(. - mins))
# nm X1799.38928 X1798.01526 X1796.64124 source color rep
#1 s001c1 18.610 5.722 0.000 1 c 1
#2 s001c2 14.211 0.000 11.990 1 c 2
#3 s001c3 0.000 16.820 21.784 1 c 3
#4 s001c4 0.000 11.447 17.792 1 c 4
#5 s001c5 6.804 0.000 3.581 1 c 5
或将其组合成一条链
x.df %>%
mutate(mins = reduce(.[grepl("^X", names(.))], pmin)) %>% # get min by row
mutate_at(vars(starts_with("X")), funs(. - mins)) %>% # take difference
select(-mins) # remove the column mins
注意:pmin
最初发布在我们的帖子中