R 遍历列表

R loop over a list

嗨,我是新来的,也是 R 的新手。 如果有人可以在这里帮助我,那就太好了。 我正在尝试制作一个 for 循环以获得所需的输出,但目前有点困难。

假设下面有一个table:

> d
  names    variables            value
1 colour   c(red, blue)         10    
2 colour   c(yellow, blue)      32    
3 colour   c(green, red, pink)  81    
4 colour   c(pink, purple)      14
5 shape    c(circle, triangle)  5
6 shape    c(rectangle)         31
7 .....

我想做的是创建一个 for 循环遍历每个名​​称的变量。 如果存在每个名称的目标变量,则将原始值设置为 0 并创建一个复制行,其值取原始值的负值。

例如,假设我们的颜色目标变量是 'red'。 我希望输出看起来像:

> d1
  names    variables            value
1 colour   c(red, blue)         0    
2 colour   c(yellow, blue)      32    
3 colour   c(green, red, pink)  0    
4 colour   c(pink, purple)      14
5 colour1  c(red, blue)         -10
6 colour2  c(green, red, pink)  -81       
7 shape    c(circle, triangle)  5
8 shape    c(rectangle)         31
7 .....

我希望我说得有道理。 如有任何帮助或意见,我们将不胜感激。

谢谢!!

你可以用 tidyverse:

  1. 首先我们使用 stringr 包中的 str_detect(它在 tidyverse 中)来识别那些具有 red ind 变量的行。
  2. 然后我们将 1 和 2 (=row_number) 添加到 names 并且将 value 乘以 -1 以获得负值。
  3. 我们使用 dplyr 包中的 bind_rows(它在 tidyverse 中)绑定到原始数​​据帧。
  4. 然后我们使用ifelse语句将变量red的值设置为0(假设原始值> 0。
  5. 我们使用 as_tibble() 删除行名,最后 arrange
library(tidyverse)

df %>% 
  filter(str_detect(variables, "red")) %>% 
  mutate(names = paste0(names, row_number()),
         value = value*-1) %>% 
  bind_rows(df) %>% 
  mutate(value = ifelse(str_detect(variables, "red") &
                          value > 0, 0, value)) %>% 
  as_tibble() %>% 
  arrange(names)
  names   variables           value
  <chr>   <chr>               <dbl>
1 colour  c(red, blue)            0
2 colour  c(yellow, blue)        32
3 colour  c(green, red, pink)     0
4 colour  c(pink, purple)        14
5 colour1 c(red, blue)          -10
6 colour2 c(green, red, pink)   -81
7 shape   c(circle, triangle)     5
8 shape   c(rectangle)           31
structure(list(names = c("colour", "colour", "colour", "colour", 
"shape", "shape"), variables = c("c(red, blue)", "c(yellow, blue)", 
"c(green, red, pink)", "c(pink, purple)", "c(circle, triangle)", 
"c(rectangle)"), value = c(10L, 32L, 81L, 14L, 5L, 31L)), class = "data.frame", row.names = c("1", 
"2", "3", "4", "5", "6"))

这是一个仅使用 Base R 的解决方案,使用 TarJae 的数据构造,用于数据帧 x:

# Create a vector with the row indeces that contain the target string:
target <- grep( 'red', x[ , 2 ] )
# Put these rows away in a separate data.frame:
stash <- x[ target, ]
# Set the value of the original rows to `0`
x[ target, 3 ] <- 0
# Set the values in the separated rows to their negative value 
stash[ , 3 ] <- stash[ , 3 ] * -1
# Modify `names` as desired:
for( i in 1 : length( stash[ , 1 ] ) ) 
    stash[ i, 1 ] <-  paste( stash[ i, 1 ], i, sep = "" )

# Insert the modified data (supposes that the dataframe is expected 
# to be sorted on the first column):
x <- rbind( x, stash )
x <- x[ order(x[ 1 ] ),  ]

这给了你

> x
     names           variables value
1   colour        c(red, blue)     0
2   colour     c(yellow, blue)    32
3   colour c(green, red, pink)     0
4   colour     c(pink, purple)    14
11 colour1        c(red, blue)   -10
31 colour2 c(green, red, pink)   -81
5    shape c(circle, triangle)     5
6    shape        c(rectangle)    31

如果您将 'red' 替换为 'blue''rectangle',这同样有效。对于您评论中的扩展问题:可以创建一个带有目标的向量(例如 c( "red", "triangle" ),然后遍历上面的代码,将每个输出写入一个列表。有关您所需输出的更多示例数据和信息将是不过需要。作为第一步,您可以尝试:

crit <- c( "rectangle", "red", "blue" )     # vector with target values
y <- list()                                 # initialize receiving list
for( j in 1 : length( crit ) )
{ 
    target <- grep( crit[ j ], x[ , 2 ] )
    stash <- x[ target, ] 
    stash[ , 3 ] <- stash[ , 3 ] * -1
    # Modify `names` as desired:
    for( i in 1 : length( stash[ , 1 ] ) ) 
        stash[ i, 1 ] <-  paste( stash[ i, 1 ], ( 10 * i + j ), sep = "" )

    # write to list element instead of overwriting original dataframe
    y[[ j ]] <- rbind( x, stash )
    y[[ j ]][ target, 3 ] <- 0      # Set the value of the original rows to `0`
    y[[ j ]] <- y[[ j ]][ order( y[[ j ]][ 1 ] ),  ]
    # here, you have a list with individual dataframes for each target value
    
    # you could merge into one joint dataframe with
    z <- Reduce( function( x, y, ... ) merge( x, y, all = TRUE, ... ), y )
}
    

产生

> z
      names           variables value
1    colour c(green, red, pink)     0
2    colour c(green, red, pink)    81
3    colour     c(pink, purple)    14
4    colour        c(red, blue)     0
5    colour        c(red, blue)    10
6    colour     c(yellow, blue)     0
7    colour     c(yellow, blue)    32
8  colour12        c(red, blue)   -10
9  colour13        c(red, blue)   -10
10 colour22 c(green, red, pink)   -81
11 colour23     c(yellow, blue)   -32
12    shape c(circle, triangle)     5
13    shape        c(rectangle)     0
14    shape        c(rectangle)    31
15  shape11        c(rectangle)   -31

这可能是进一步工作的良好开端