如何使用[row,col] distance索引跨特定列执行row summs for循环

sh7euo9m  于 2023-02-01  发布在  其他
关注(0)|答案(3)|浏览(132)

重新规划前面的问题,但希望更清晰+dput()。
我正在处理下面的数据,它几乎类似于键:值对,这样每个"type"变量都有一个对应的变量,该变量包含每行的"total"值。

structure(list(type3a1 = c(2L, 6L, 5L, NA, 1L, 3L, NA), type3b1 = c(NA, 
3L, 1L, 5L, 6L, 3L, NA), type3a1_arc = c(1L, 2L, 5L, 4L, 5L, 
4L, NA), type3b1_arc = c(2L, 2L, 3L, 4L, 1L, 1L, NA), testing = c("Yes", 
NA, "No", "No", NA, "Yes", NA), cars = c(5L, 12L, 1L, 6L, NA, 
2L, NA), house = c(5L, 4L, 0L, 5L, 0L, 10L, NA), type3a2 = c(50L, 
NA, 20L, 4L, 5L, NA, NA), type3b2 = c(10L, 10L, 15L, 1L, 3L, 
1L, NA), type3a2_arc = c(50L, 25L, 30L, 10L, NA, 10L, NA), type3b2_arc = c(NA, 
20L, 10L, 50L, 5L, 1L, NA), X = c(NA, NA, NA, NA, NA, NA, NA)), class = "data.frame", row.names = c(NA, 
-7L))

我尝试做一个求和循环,遍历每一行,扫描每个"type"变量(即type3a1、type3b1、type3c1等)。每个"type"都有一个匹配的变量,包含它的"total"值(即type3a2、type3b2、type3c2等)。
流程:
1.检查"type"变量是否包含(1、2、3、4或5)中的值。
1.如果该类型列的[row,col]值在(1:5)中,则从其当前[row,col]索引中移动7列以获取其总值并准备求和。
1.检查完每个"type"变量后,将所有收集到的"total"值相加,并放入一个新的总体总计列。
基本上,我希望得到如下所示的总值:

    • 第一行**显示总数为100,因为类型3b1的值为"NA",而该值不在(1:5)中。因此,在行求和中不考虑其总配对(即,+7列远=单元格值"10")。

与之前的尝试相比,我这次的方法是使用for循环,并依赖于基于一列与另一列之间距离的索引。我在使用dplyr/mutate方法时遇到了很多麻烦,并且在类型的可变性方面遇到了很多问题:总名称配对(即命名约定中没有模式,数据非常混乱)...

# Matching pairing variables (i.e. type_vars:"type3a1" with total_vars:"type3a2") 
type_vars <- c("type3a1", "type3b1", "type3a1_arc", "type3b1_arc")
total_vars <- c("type3a2", "type3b2", "type3a2_arc", "type3b2_arc")

valid_list <- c(1,2,3,4,5)
totals = list()

for(row in 1:nrow(df)) {
  sum = 0
  for(col in type_vars) {
    if (df[row,col] %in% valid_list) {
      sum <- sum + (df[row,col+7])
    }
  }
  totals <- sum
}

我希望这是正确的方法,但在任何一种情况下,代码都会在sum <- sum + (df[row,col+7])行给我一个错误,其中:Error in col + 7 : non-numeric argument to binary operator.
这很奇怪,因为如果我手动执行此操作,只指示df[1,1+2],它会给我一个值"1",这是上面df中交集[row1, type3a1_arc]的值。
任何帮助或援助将不胜感激。

cmssoen2

cmssoen21#

您收到的错误是因为原始for循环中的col遍历了type_vars,它是一个字符数据类型。一种解决方法是使用which()函数引用type_vars的列索引。下面是一个解决方案,只需对for循环进行一些修改:

totals <- c()

for(row in 1:nrow(df)) {
    sum = 0
    for(col in which(names(df) %in% type_vars)) {
        if (df[row,col] %in% valid_list) {
            sum <- sum(c(sum, (df[row,col+7])), na.rm=T)
        }
    }
    totals[row] <- sum
}
df$totals <- totals
df$totals
[1] 100  55  75  61  10  12   0
t5fffqht

t5fffqht2#

下面是使用tidyverse的一种方法-循环across名称为matches "type"后跟一个或多个数字的列(\\d+),一个字母([a-z])和数字2,然后通过替换列名来获取对应的列名(cur_column())子字符串数字2为1,使用cur_data()获取值,使用%in%创建逻辑向量,对(!)和replace中不符合1:5的求反为NA,然后使用rowSumsna.rm = TRUE进行换行以获取total

library(dplyr)
library(stringr)
df1 %>% 
 mutate(total = rowSums(across(matches('^type\\d+[a-z]2'), ~ 
  replace(.x, !cur_data()[[str_replace(cur_column(),
   "(\\d+[a-z])\\d+", "\\11")]] %in% 1:5, NA)), na.rm = TRUE))
  • 输出
type3a1 type3b1 type3a1_arc type3b1_arc testing cars house type3a2 type3b2 type3a2_arc type3b2_arc  X total
1       2      NA           1           2     Yes    5     5      50      10          50          NA NA   100
2       6       3           2           2    <NA>   12     4      NA      10          25          20 NA    55
3       5       1           5           3      No    1     0      20      15          30          10 NA    75
4      NA       5           4           4      No    6     5       4       1          10          50 NA    61
5       1       6           5           1    <NA>   NA     0       5       3          NA           5 NA    10
6       3       3           4           1     Yes    2    10      NA       1          10           1 NA    12
7      NA      NA          NA          NA    <NA>   NA    NA      NA      NA          NA          NA NA     0

或者也可以使用两个across(假设列是按顺序排列的)

df1 %>%
   mutate(total = rowSums(replace(across(8:11), 
     !across(1:4, ~ .x %in% 1:5), NA), na.rm = TRUE))
  • 输出
type3a1 type3b1 type3a1_arc type3b1_arc testing cars house type3a2 type3b2 type3a2_arc type3b2_arc  X total
1       2      NA           1           2     Yes    5     5      50      10          50          NA NA   100
2       6       3           2           2    <NA>   12     4      NA      10          25          20 NA    55
3       5       1           5           3      No    1     0      20      15          30          10 NA    75
4      NA       5           4           4      No    6     5       4       1          10          50 NA    61
5       1       6           5           1    <NA>   NA     0       5       3          NA           5 NA    10
6       3       3           4           1     Yes    2    10      NA       1          10           1 NA    12
7      NA      NA          NA          NA    <NA>   NA    NA      NA      NA          NA          NA NA     0

或者使用base R

df1$total <- rowSums(mapply(\(x, y) replace(y, !x %in% 1:5, NA), 
      df1[1:4], df1[8:11]), na.rm = TRUE)
df1$total
[1] 100  55  75  61  10  12   0
tcomlyy6

tcomlyy63#

下面是一个R基溶液:

valid_vals <- sapply(type_vars, \(col) df[, col] %in% valid_list)

temp <- df[, total_vars]
temp[!valid_vals] <- NA

df$total <- rowSums(temp, na.rm = TRUE)
df$total
# [1] 100  55  75  61  10  12   0

相关问题