147

在下面编码的 R 数据帧中,我想将B 出现的所有时间替换为b.

junk <- data.frame(x <- rep(LETTERS[1:4], 3), y <- letters[1:12])
colnames(junk) <- c("nm", "val")

这提供了:

   nm val
1   A   a
2   B   b
3   C   c
4   D   d
5   A   e
6   B   f
7   C   g
8   D   h
9   A   i
10  B   j
11  C   k
12  D   l

我最初的尝试是使用这样的forif语句:

for(i in junk$nm) if(i %in% "B") junk$nm <- "b"

但我相信你可以看到,这替换了junk$nmwith的所有值b。我可以看到为什么这样做,但我似乎无法让它仅替换原始值为 junk$nm 的那些情况B

注意:我设法解决了这个问题,gsub但为了学习 RI,我仍然想知道如何让我的原始方法发挥作用(如果可能的话)

4

10 回答 10

248

更容易将 nm 转换为字符,然后进行更改:

junk$nm <- as.character(junk$nm)
junk$nm[junk$nm == "B"] <- "b"

编辑:如果您确实需要将 nm 作为因素进行维护,请在最后添加:

junk$nm <- as.factor(junk$nm)
于 2011-04-28T20:11:04.490 回答
47

另一种替换值的有用方法

library(plyr)
junk$nm <- revalue(junk$nm, c("B"="b"))
于 2013-12-14T16:27:03.313 回答
29

简短的回答是:

junk$nm[junk$nm %in% "B"] <- "b"

看看R 简介中的索引向量(如果你还没有读过的话)。


编辑。正如评论中所注意到的,此解决方案适用于字符向量,因此您的数据失败。

对于因素,最好的方法是改变水平:

levels(junk$nm)[levels(junk$nm)=="B"] <- "b"
于 2011-04-28T20:03:38.517 回答
21

由于您显示的数据是因素,因此它使事情变得有些复杂。@diliop 的答案通过转换为nm字符变量来解决问题。要回到原始因素,还需要进一步的步骤。

另一种方法是操纵现有因素的水平。

> lev <- with(junk, levels(nm))
> lev[lev == "B"] <- "b"
> junk2 <- within(junk, levels(nm) <- lev)
> junk2
   nm val
1   A   a
2   b   b
3   C   c
4   D   d
5   A   e
6   b   f
7   C   g
8   D   h
9   A   i
10  b   j
11  C   k
12  D   l

这很简单,我经常忘记levels().

编辑:正如@Seth 在评论中指出的那样,这可以在单行中完成,而不会失去清晰度:

within(junk, levels(nm)[levels(nm) == "B"] <- "b")
于 2011-04-28T20:36:14.840 回答
12

在一个命令中执行此操作的最简单方法是使用which命令,并且也不需要通过执行以下操作将因子更改为字符:

junk$nm[which(junk$nm=="B")]<-"b"
于 2012-01-07T13:26:03.543 回答
5

您已经在其中创建了一个因子变量,nm因此您要么需要避免这样做,要么为因子属性添加一个额外的级别。您还应该避免<-在 data.frame() 的参数中使用

选项1:

junk <- data.frame(x = rep(LETTERS[1:4], 3), y =letters[1:12], stringsAsFactors=FALSE)
junk$nm[junk$nm == "B"] <- "b"

选项 2:

levels(junk$nm) <- c(levels(junk$nm), "b")
junk$nm[junk$nm == "B"] <- "b"
junk
于 2011-04-28T20:18:39.363 回答
2

如果您正在使用字符变量(注意stringsAsFactors这里是错误的),您可以使用替换:

junk <- data.frame(x <- rep(LETTERS[1:4], 3), y <- letters[1:12], stringsAsFactors = FALSE)
colnames(junk) <- c("nm", "val")

junk$nm <- replace(junk$nm, junk$nm == "B", "b")
junk
#    nm val
# 1   A   a
# 2   b   b
# 3   C   c
# 4   D   d
# ...
于 2018-02-20T15:28:44.230 回答
2

你也可以用ifelse,很简单易懂

junk$val <- ifelse(junk$nm == "B", "b", junk$val)

如果你还想通过for loop正确的方式去做

for(i in 1:nrow(junk)){
  if(junk[i, "nm"] == "B"){
    junk[i, "val"] <- "b"
  }
}

junk
> junk
   nm val
1   A   a
2   B   b
3   C   c
4   D   d
5   A   e
6   B   b
7   C   g
8   D   h
9   A   i
10  B   b
11  C   k
12  D   l
于 2021-03-31T05:07:13.757 回答
0
stata.replace<-function(data,replacevar,replacevalue,ifs) {
  ifs=parse(text=ifs)
  yy=as.numeric(eval(ifs,data,parent.frame()))
  x=sum(yy)
  data=cbind(data,yy)
  data[yy==1,replacevar]=replacevalue
  message=noquote(paste0(x, " replacement are made"))
  print(message)
  return(data[,1:(ncol(data)-1)])
}

使用下面的行调用此函数。

d=stata.replace(d,"under20",1,"age<20")
于 2019-04-08T06:47:29.930 回答
0

我遇到了同样的问题,你也可以对每一列做同样的事情,

 fix_junk <- function(x){
      #x <- as.character(x)
      x[x == "B"] <- "b"
      x
    }
    junk[] <- lapply(junk, fix_junk); junk # junk[] to get a data frame rather than a list
    junk[1:3] <- lapply(junk[1:3], fix_junk); junk
于 2021-04-16T13:55:19.607 回答