H,我是 R 的新手,我正在尝试编写一个函数来创建一个新的数据框,该数据框描述了减去原始数据集中彼此相邻的每两列的结果。想象一下这是可能的数据(尽管我有很多变量)
obs var1 var2 var3
1 5 10 14
2 6 11 15
3 7 12 16
4 8 13 17
输出应该是这个样子
obs var2_1 var3_2
1 5 4
2 5 4
3 5 4
4 5 4
非常感谢您!
这基本上是-
df[-c(1, 2)] - df[-c(1, ncol(df))]
# var2 var3
#1 5 4
#2 5 4
#3 5 4
#4 5 4
使其更具可扩展性并符合您的预期输出 -
#Create a temporary dataframe to keep only the columns we are interested in
temp_df <- df[-1]
#Save ncol value in a variable to avoid recalculating
n <- ncol(temp_df)
#Create new column names
new_cols <- paste0('var', 2:n,'_', 1:(n-1))
#add the calculated columns to temporary df
temp_df[new_cols] <- temp_df[-1] - temp_df[-n]
#keeping only interested columns.
cbind(df[1], temp_df[new_cols])
# obs var2_1 var3_2
#1 1 5 4
#2 2 5 4
#3 3 5 4
#4 4 5 4
@Mael 的答案肯定更紧凑,但您也可以使用
dplyr
:
您可以创建一个变量名向量,这些变量名将参与减法。然后,从第二个开始循环遍历名称。您可以创建一个变量,即第 i 个减去前一个。
library(dplyr)
dat <- tibble::tribble(
~obs, ~var1, ~var2, ~var3,
1, 5, 10, 14,
2, 6, 11, 15,
3, 7, 12, 16,
4, 8, 13, 17)
ndat <- names(dat)
## remove obs from list of variables
ndat <- ndat[-1]
for(i in 2:length(ndat)){
newvar <- paste(ndat[i], ndat[(i-1)], sep="_")
dat <- dat %>%
mutate( {{newvar}} := .data[[ndat[i]]] - .data[[ndat[(i-1)]]])
}
dat %>% select(-all_of(ndat))
#> # A tibble: 4 × 3
#> obs var2_var1 var3_var2
#> <dbl> <dbl> <dbl>
#> 1 1 5 4
#> 2 2 5 4
#> 3 3 5 4
#> 4 4 5 4
创建于 2023-03-01 与 reprex v2.0.2
一个
dplyr
解决方案:
library(dplyr)
df %>%
mutate(pick(var2:var3) - pick(var1:var2), .keep = "unused")
# obs var2 var3
# 1 1 5 4
# 2 2 5 4
# 3 3 5 4
# 4 4 5 4
您可以使用
apply
进行逐行差异。第二个参数 1
表示函数 diff
应用于行。如果需要,转换为data.frame
。
cbind(df[1], t(apply(df[-1], 1, diff)))
obs var2 var3
1 1 5 4
2 2 5 4
3 3 5 4
4 4 5 4
也可以通过旋转来实现:
library(dplyr)
library(tidyr)
df |>
pivot_longer(-obs, names_prefix = "var") |>
mutate(name = paste0("var", name, "_", lag(name)),
value = value-lag(value),
.by = "obs") |>
na.omit() |>
pivot_wider(id_cols = obs)
输出:
# A tibble: 4 × 3
obs var2_1 var3_2
<dbl> <dbl> <dbl>
1 1 5 4
2 2 5 4
3 3 5 4
4 4 5 4