R-dplyr across:从基于索引的列范围中减去1列

nxowjjhe  于 2023-05-20  发布在  其他
关注(0)|答案(2)|浏览(119)

这是我的第一篇文章,我对R相对较新,所以如果我的框架不好,我道歉。
我在其他地方没有发现这个问题,但最初的方法与这里描述的有点相似:
How to mutate several columns by column index rather than column name using across?
我有一个包含时间序列数据的数据框,我想从一系列连续列中删除特定列。在下面的示例中,1 R中的值将从列1A、1B和1C中删除。同样地,2 R中的值将从2A、2B和2C中移除。
所以像这样的数据框

t | 1A | 1B| 1C|1RMV| 2A | 2B| 2C|2RMV| 
- | - -|- -|- -| - -| - -|- -|- -|- - | 
1 | 1  | 4 | 7 | 3  | 1  | 4 | 7 | 1  |   . . . . . . .
2 | 2  | 5 | 8 | 2  | 2  | 5 | 8 | 2  |
3 | 3  | 6 | 9 | 1  | 3  | 6 | 9 | 3  |

会变成这样

t | 1A | 1B| 1C|1RMV| 2A | 2B| 2C|2RMV| 
 -| - -|- -|- -| - -| - -|- -|- -|- - | 
1 | -2 | 1 | 4 | 3  | 0  | 3 | 6 | 1  |   . . . . . . .
2 | 0  | 3 | 6 | 2  | 0  | 3 | 6 | 2  |
3 | 2  | 5 | 8 | 1  | 0  | 3 | 6 | 3  |

我以前执行过这个‘手动‘,它的工作刚刚好,但由于试图使这个过程更自动化,我遇到了问题。
由于每个组中的列数(1A,1B,1C,而2A,2B,2C,2D,2 E等)不同,我最初创建了一个列表,其中包含所有列的索引位置,我想从其他列中减去这些列,如下所示:

#Return TRUE only for columns to be removed
df_boolean <- str_ends(colnames(df), "RMV")

#Create a 1D vector with elements of index positions of columns to be removed in Data
col_number <- ncol(Intensity_Raw_Data)
remove_indices <- c()
for(i in 1:col_number){
  if(df_boolean[i] == TRUE){
    remove_indices <- c(background_indices, i)
  }
}

然后我使用across from dplyr执行减法,如下所示:

group_number <- length(remove_indices)

#Calculate subtraction for first group, probably way to do it in one loop but first column is the time column and I'm lazy

df_Subtracted <- df %>%
mutate(across(2:(remove_indices[1] - 1), ~.  - df[(remove_indices[1])]))

#Calculate subtracction for remaining groups
for(i in 2:group_number){
  df_Subtracted <- df_Subtracted %>%
  mutate(across((remove_indices[i-1] + 1):(remove_indices[i] - 1), ~.x - df[(remove_indices[i])]))

在这里我遇到了我的问题,当手动运行这个(即在across()中手动键入列名),列名保持不变。然而,当我使用上面的代码运行这个时,列名被重命名为:
1A$1R 1B$1R 1C$1R。...... 2A$2R 2B$2R 2C$2R 2D$2R。......
虽然View()中的输出看起来是正确的,但使用str()显示输出(df_Subtracted)中的每一列实际上是一个1变量 Dataframe 。
我不知道是什么原因导致这种情况发生,但我认为这可能是与我如何索引的列被删除的交叉。任何帮助将不胜感激!

**
-更新
**

我通过使用Akrun in this post使用的方法对GuedesBF anwser进行了轻微的修改,以生成按列名划分的数据的通用anwser。

df_subtracted_split <- df %>%
  split.default(sub('\\d+', '', names(df))) %>%
  lapply(function(x) {names(x)[ncol(x)] <- "RMV";x}) %>%
  map(~mutate(.x, across(1:last_col(1), ~.x - RMV))) 
 
 
df_subtracted <- do.call(qpcR:::cbind.na, Data_Final)

由于某种原因,list_rbind/list_cbind导致丢弃
列时,我读到here,它可能是我的 Dataframe 中的某些组缺少行的结果,因此我使用了qpcR中的cbind.na
感谢GuedesBF和peter 861222!

yqlxgs2m

yqlxgs2m1#

如果我们将data.frame split.default()到一个类似data.frames的列表中,执行必要的操作,最后将列表bind回到一个data.frame中,这会变得更容易。

library(dplyr)
library(readr)
library(purrr)

df %>%
    select(-t) %>% 
    split.default(parse_number(names(.)) %>%
    map(~mutate(.x, across(c(2A, 2B, 2C), \(x) x - cur_data[[4]])) %>%
    list_rbind()
qyuhtwio

qyuhtwio2#

这应该可以工作:

pivot_longer(df,cols=-1,names_pattern="(\\d)(\\w+)",names_to=c("id","name")) %>%
  mutate(value=case_when(name=="RMV"~value,
                         T~value-value[name=="RMV"]),.by=c("t","id")) %>%
  pivot_wider(names_from= c("id","name"),names_sep="") 

      t  `1A`  `1B`  `1C` `1RMV`  `2A`  `2B`  `2C` `2RMV`
  <dbl> <dbl> <dbl> <dbl>  <dbl> <dbl> <dbl> <dbl>  <dbl>
1     1    -2     1     4      3     0     3     6      1
2     2     0     3     6      2     0     3     6      2
3     3     2     5     8      1     0     3     6      3

相关问题