根据78*2其他变量dplyr的列输入计算新(78)变量
我想在“两列”对的基础上做一个简单的减法,a1…n和c1…n系列,在dplyr中创建第三列b1…n,超过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
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')