用多列中的多个值替换多个字符? R

Replace multiple characters with multiple values in multiple columns? R

另一个线程解决了类似的问题very nicely

但我想做的是摆脱我的类似问题中的一些冗余。

使用他们的例子:

df <- data.frame(name = rep(letters[1:3], each = 3), foo=rep(1:9),var1 = letters[1:3], var2 = rep(3:5, each = 3))

创造:

df
  name foo var1 var2
1    a   1    a    3
2    a   2    a    3
3    a   3    a    3
4    b   4    b    4
5    b   5    b    4
6    b   6    b    4
7    c   7    c    5
8    c   8    c    5
9    c   9    c    5

但是我需要怎么做才能用唯一值替换多个字符?

a=1
b=2
c=3

我试过了:

df[,c(4,6)] <- lapply(df[,c(4,6)], function(x) replace(x,x %in% "a", 1), 
                                                             replace(x,x %in% "b", 2),
                                                             replace(x,x %in% "c", 3))

z<- c("a","b","c")
y<- c(1,2,3)
df[,c(1,3)] <- lapply(df[,c(1,3)], function(x) replace(x,x %in% z, y))

但似乎都不起作用。

谢谢。

一个简单的 for 循环就可以解决问题:

for (i in 1:length(z)) {
  df[df==z[i]] <- y[i]
}

df

  name foo var1 var2
1    1   1    1    3
2    1   2    2    3
3    1   3    3    3
4    2   4    1    4
5    2   5    2    4
6    2   6    3    4
7    3   7    1    5
8    3   8    2    5
9    3   9    3    5

您可以使用 lookup 向量结合 apply:

z <- c("a","b","c")
y <- c(1,2,3)

lookup <- setNames(y, z)

df[,c(1,3)] <- apply(df[,c(1,3)], 2, function(x) lookup[x])
df

这个returns

  name foo var1 var2
1    1   1    1    3
2    1   2    2    3
3    1   3    3    3
4    2   4    1    4
5    2   5    2    4
6    2   6    3    4
7    3   7    1    5
8    3   8    2    5
9    3   9    3    5

如果您愿意接受 tidyverse 方法:

library(tidyverse)

df_new <- df %>%
  mutate(across(c(var1, name), ~case_when(. == 'a' ~ 1,
                                          . == 'b' ~ 2,
                                          . == 'c' ~ 3)))

df_new

  name foo var1 var2
1    1   1    1    3
2    1   2    2    3
3    1   3    3    3
4    2   4    1    4
5    2   5    2    4
6    2   6    3    4
7    3   7    1    5
8    3   8    2    5
9    3   9    3    5

请注意,此代码仅在您更改列的所有值时才有效。例如。如果您的 var1 列中有一个“d”,您没有将其转换为数字,它将更改为 NA。

您可以使用dplyr::recode

df <- data.frame(name = rep(letters[1:3], each = 3), foo=rep(1:9),var1 = letters[1:3], var2 = rep(3:5, each = 3))


library(dplyr, warn.conflicts = FALSE)

df %>% 
  mutate(across(c(name, var1), ~ recode(., a = 1, b = 2, c = 3)))
#>   name foo var1 var2
#> 1    1   1    1    3
#> 2    1   2    2    3
#> 3    1   3    3    3
#> 4    2   4    1    4
#> 5    2   5    2    4
#> 6    2   6    3    4
#> 7    3   7    1    5
#> 8    3   8    2    5
#> 9    3   9    3    5

reprex package (v2.0.1)

于 2021-10-19 创建

Across 会将 ~ recode(., a = 1, b = 2, c = 3) 定义的函数应用于 namevar1

使用~.是在across中定义函数的另一种方法。此函数等效于 function(x) recode(x, a = 1, b = 2, c = 3) 定义的函数,您可以在 across 中使用该代码而不是 ~ 形式,它会给出相同的结果。我知道的唯一名称是它在 ?across 中的名称,即“purrr 风格的 lambda 函数”,因为 purrr 包是第一个使用公式以这种方式定义函数的包。

如果想看公式创建的实际函数,可以看rlang::as_function(~ recode(., a = 1, b = 2, c = 3)),虽然比上面的稍微复杂一点,支持..1的使用,..2..3 这里没有使用。

现在 R 支持下面定义函数的更简单方法,这个 purrr 风格的函数可能不再有用,这样写只是一个老习惯。

df <- data.frame(name = rep(letters[1:3], each = 3), foo=rep(1:9),var1 = letters[1:3], var2 = rep(3:5, each = 3))

library(dplyr, warn.conflicts = FALSE)

df %>% 
  mutate(across(c(name, var1), \(x) recode(x, a = 1, b = 2, c = 3)))
#>   name foo var1 var2
#> 1    1   1    1    3
#> 2    1   2    2    3
#> 3    1   3    3    3
#> 4    2   4    1    4
#> 5    2   5    2    4
#> 6    2   6    3    4
#> 7    3   7    1    5
#> 8    3   8    2    5
#> 9    3   9    3    5

reprex package (v2.0.1)

于 2021-10-19 创建
# Import data: df => data.frame
df <- data.frame(name = rep(letters[1:3], each = 3), foo=rep(1:9),var1 = letters[1:3], var2 = rep(3:5, each = 3))

# Function performing a mapping replacement:
# replaceMultipleValues => function() 
replaceMultipleValues <- function(df, mapFrom, mapTo){
  # Extract the values in the data.frame: 
  # dfVals => named character vector
  dfVals <- unlist(df)
  
  # Get all values in the mapping & data 
  # and assign a name to them: tmp1 => named character vector 
  tmp1 <- c(
    setNames(mapTo, mapFrom), 
    setNames(dfVals, dfVals)
  )

  # Extract the unique values: 
  # valueMap => named character vector
  valueMap <- tmp1[!(duplicated(names(tmp1)))]
  
  # Recode the values, coerce vectors to appropriate
  # types: res => data.frame
  res <- type.convert(
    data.frame(
      matrix(
        valueMap[dfVals], 
        nrow = nrow(df),
        ncol = ncol(df),
        dimnames = dimnames(df)
      )
    )
  )
  
  # Explicitly define the returned object: data.frame => env
  return(res)
}

# Recode values in data.frame: 
# res => data.frame
res <- replaceMultipleValues(
  df, 
  c("a", "b", "c"), 
  c("1", "2", "3")
)

# Print data.frame to console: 
# data.frame => stdout(console)
res