根据78*2其他变量dplyr的列输入计算新(78)变量

根据78*2其他变量dplyr的列输入计算新(78)变量,r,dplyr,mutate,R,Dplyr,Mutate,我想在“两列”对的基础上做一个简单的减法,a1…n和c1…n系列,在dplyr中创建第三列b1…n,超过78个“对”。但是,我不知道如何正确地调用列并在每个列对上运行它 df var C400.0 C403.7 C407.1 A399.6 A403.4 A406.4 V1 1.176 1.149 1.111 0.767 0.736 0.699 V2 1.192 1.160 1.127 0.770 0.738 0.707 V3 1

我想在“两列”对的基础上做一个简单的减法,a1…n和c1…n系列,在dplyr中创建第三列b1…n,超过78个“对”。但是,我不知道如何正确地调用列并在每个列对上运行它

df
var C400.0   C403.7  C407.1  A399.6  A403.4   A406.4
V1  1.176    1.149   1.111   0.767   0.736    0.699
V2  1.192    1.160   1.127   0.770   0.738    0.707
V3  1.223    1.1918  1.154   0.775   0.744    0.715
我试过:

b_names <- c( "B400",   "B403",   "B407")
df_b  <- mutate_at(df,vars(C400.0:C407.1), .funs(b_names= ., vars(C400.0:C407.1)-vars(A399.6:A403.4)))

这里有一个
tidyverse
解决方案,它首先将数据整理成长格式

# load packages
require(stringr)
require(tidyverse)

# your example data
df <- read_table('var C400.0   C403.7  C407.1  A399.6  A403.4   A406.4
V1  1.176    1.149   1.111   0.767   0.736    0.699
V2  1.192    1.160   1.127   0.770   0.738    0.707
V3  1.223    1.1918  1.154   0.775   0.744    0.715')

# generating obtained values
df %>%
    gather(col, value, -var) %>%
    mutate(col_letter = str_extract(col, 'A|C')) %>%
    group_by(var, col_letter) %>%
    mutate(col_position = row_number()) %>%
    group_by(var) %>%
    select(-col) %>%
    spread(col_letter, value) %>%
    mutate(dif = C - A) %>%
    select(var, col_position, dif) %>%
    spread(col_position, dif, sep='_') %>%
    bind_cols(df, .)
#加载包
要求(stringr)
要求(整洁的人)
#您的示例数据
df%
聚集(列,值,-var)%>%
突变(col_字母=str_提取(col,'A | C'))%>%
分组依据(变量、列字母)%>%
变异(列位置=行编号())%>%
分组依据(var)%>%
选择(-col)%>%
价差(列字母,值)%>%
突变(dif=C-A)%>%
选择(变量、列位置、dif)%>%
排列(列位置、dif、sep=''列''>%
绑定cols(df,.)

这不会获得输出中所需的列名,但它确实包含您要求的所有值。如果愿意,您可以在此时手动重命名。

此解决方案不使用
dplyr
,但可以实现您想要的功能

library(readr)
df <- read_table('var C400.0   C403.7  C407.1  A399.6  A403.4   A406.4
V1  1.176    1.149   1.111   0.767   0.736    0.699
V2  1.192    1.160   1.127   0.770   0.738    0.707
V3  1.223    1.1918  1.154   0.775   0.744    0.715')
首先,我们提取“C”名称和“A”名称。这假设它们已经就绪,但您在问题中显示的结果没有明确说明A406.4与C403.7是如何匹配的

然后,我们可以基于列名对df进行子集划分,并对生成的子集data.frames进行元素相减。我们更改名称并执行一个简单的
cbind

原液

mapply(函数(x,y){
num=str_extract(x,“[0-9]+”)
df[[paste0(“B”,num)]]=df[[x]]-df[[y]]
分配(“df”,df,envir=globalenv())
返回(空)
},cNames,aNames)

然后我编写了一个函数,它接受两个输入,并使用
mappy
在“C”名称和“a”名称集合之间循环。在每个组合中,我们提取“C”名称的编号,并将其粘贴到“B”上,并将其分配为“C”-“a”的差值。然后,因为我们正在构建一组新列,所以我将结果
df
分配回全局环境(大的旧副作用)。mapply返回一组空值,但df已更新为包含B列。这将保留原始的广域数据结构,而无需使用
tidyverse

以长格式获取数据,而不使用列名编码的值
tidyr::gather
Reforme2::melt
将对此有所帮助。或者,只需在base中定位:
cbind(df,setNames(df[2:4]-df[5:7],b_names))
。首先确保所有内容都按正确的顺序排列。我想重塑2和tidyr不会融化多个列。。?有了data.table,您可以使用patterns helper函数
data.table(df)%%melt(meas=patterns(“A”、“C”),value.name=C(“A”、“C”))%%>%mutate(B=C-A)
而不是
mapply
assign
,您只需执行
new\cols=df[cNames]
,一次设置所有的名称
setNames>(new_cols,paste0(“B”,str_extract(cNames,[0-9]+”))
,最后是
result=cbind(df,new_cols)
。无需循环/应用,全部矢量化,无不良副作用。@Gregor谢谢。显然我没有想到这一点-添加了矢量化解决方案。另一个(次要)建议-由于您已经对
aNames
cNames
使用了
grep
,您可以通过对新列名使用
grep
而不是
stru extract
来完全消除
stringr
依赖关系。除非我偏离了基准,
grep
使用
value=T
返回整个str如果它与搜索模式匹配,则不只是匹配的部分。
sub
可以在正则表达式被修改的情况下使用,
regexpr
可以提供运行
substr
的信息,但没有一个比
stringr
更好。我将添加一个
sub
备选方案作为示例。啊,你说得对!我使用了一个带有n的玩具示例编号为1:10,并认为
grep
输出匹配元素1:10实际上是从字符串中提取1:10。
library(readr)
df <- read_table('var C400.0   C403.7  C407.1  A399.6  A403.4   A406.4
V1  1.176    1.149   1.111   0.767   0.736    0.699
V2  1.192    1.160   1.127   0.770   0.738    0.707
V3  1.223    1.1918  1.154   0.775   0.744    0.715')