【问题标题】:How do I replace values within a data frame with a string in R?如何用 R 中的字符串替换数据框中的值?
【发布时间】:2012-09-04 10:04:36
【问题描述】:

短版:如何将数据框中的值替换为在另一个数据框中找到的字符串?

加长版:我是一名研究多种蜜蜂的生物学家。我有一个包含数千只蜜蜂的数据集。每行都有一个唯一的蜜蜂 ID # 以及有关该标本的所有相关信息(捕获数据、GPS 位置等)。没有输入每只蜜蜂的物种信息,因为识别它们需要很长时间。在 IDing 时,我最终得到了一盒数百只蜜蜂,它们都是同一物种。我将这些输入到一个单独的数据框中。我正在尝试编写代码,当我识别蜜蜂时,将使用物种信息(家庭、属、物种、性别等)更新原始数据文件。目前,在原始数据文件中,物种信息是空白的,并且在 R 中被解释为 NA。我想让 R 找到所有唯一的蜜蜂 ID #并填写物种信息,但我无法弄清楚如何用字符串替换 NA 值(例如“Andrenidae”)

这是我正在尝试做的一个简单示例:

rawData<-data.frame(beeID=c(1:20),family=rep(NA,20))
speciesInfo<-data.frame(beeID=seq(1,20,3),family=rep("Andrenidae",7))

rawData[rawData$beeID == 4,"family"]  <- speciesInfo[speciesInfo$beeID == 4,"family"]

所以,我将根据需要替换内容,但使用数字而不是姓氏(字符串)。我最终想做的是编写一个小循环来添加所有物种信息,例如:

for (i in speciesInfo$beeID){
  rawData[rawData$beeID == i,"family"]  <- speciesInfo[speciesInfo$beeID == i,"family"]
}

提前感谢您的任何建议!

干杯,

扎克

编辑:

我刚刚注意到下面的前两种方法每次都会添加一个新列,如果我需要多次添加物种信息(我通常会这样做),这会导致问题。例如:

rawData<-data.frame(beeID=c(1:20),family=rep(NA,20))
Andrenidae<-data.frame(beeID=seq(1,20,3),family=rep("Andrenidae",7))
Halictidae<-data.frame(beeID=seq(1,20,3)+1,family=rep("Halictidae",7))

# using join
library(plyr)
rawData <- join(rawData, Andrenidae, by = "beeID", type = "left")
rawData <- join(rawData, Halictidae, by = "beeID", type = "left")

# using merge
rawData <- merge(x=rawData,y=Andrenidae,by='beeID',all.x=T,all.y=F)
rawData <- merge(x=rawData,y=Halictidae,by='beeID',all.x=T,all.y=F)

有没有办法折叠列以便我拥有一个统一的数据框?还是一种更新 rawData 而不是每次都添加新列的方法?提前致谢!

【问题讨论】:

    标签: string r replace na


    【解决方案1】:

    data.table 解决方案将节省内存和时间。

    • 请注意,rbindlist 需要stringsAsFactors = F(do.call(rbind,list) / rbind 的超快速版本)
    • 我已将另一列作为虚拟数据添加到 rawData 对象并删除了族。

    创建数据 -

    rawData <- data.frame(beeID = c(1:20), other_stuff = sample(letters, 20), stringsAsFactors = F)
    Andrenidae <- data.frame(beeID = seq(1, 20, 3), family = rep("Andrenidae", 7), stringsAsFactors = F)
    Halictidae <- data.frame(beeID = seq(1, 20 , 3)+  1, family = rep("Halictidae", 7), stringsAsFactors = F)
    library(data.table)
    # convert to data.table
    rawDT <- as.data.table(rawData)
    # combine the list of Species-specific data.frames into a large data.table
    speciesInfo <- rbindlist(list(Andrenidae, Halictidae))
    # set the keys, to allow efficient use of data.table and its merging 
    # abilities. The keys are the same for both 
    setkeyv(rawDT, 'beeID')
    setkeyv(speciesInfo, 'beeID')
    # merge by key 
    speciesInfo[rawDT, nomatch = NA]
    ## beeID     family other_stuff
    ## 1:     1 Andrenidae           s
    ## 2:     2 Halictidae           x
    ## 3:     3         NA           i
    ## 4:     4 Andrenidae           e
    ## 5:     5 Halictidae           v
    ## 6:     6         NA           q
    ## 7:     7 Andrenidae           w
    ## 8:     8 Halictidae           c
    ## 9:     9         NA           u
    ## 10:    10 Andrenidae           z
    ## 11:    11 Halictidae           y
    ## 12:    12         NA           a
    ## 13:    13 Andrenidae           l
    ## 14:    14 Halictidae           r
    ## 15:    15         NA           h
    ## 16:    16 Andrenidae           o
    ## 17:    17 Halictidae           n
    ## 18:    18         NA           g
    ## 19:    19 Andrenidae           p
    ## 20:    20 Halictidae           m
    

    rawDT[speciesInfo]
    
    ##    beeID other_stuff     family
    ## 1:     1           s Andrenidae
    ## 2:     2           x Halictidae
    ## 3:     4           e Andrenidae
    ## 4:     5           v Halictidae
    ## 5:     7           w Andrenidae
    ## 6:     8           c Halictidae
    ## 7:    10           z Andrenidae
    ## 8:    11           y Halictidae
    ## 9:    13           l Andrenidae
    ## 10:   14           r Halictidae
    ## 11:   16           o Andrenidae
    ## 12:   17           n Halictidae
    ## 13:   19           p Andrenidae
    ## 14:   20           m Halictidae
    

    你对哪些数据感兴趣

    【讨论】:

      【解决方案2】:

      这是我认为对您有用的功能。这使用match 在注释数据框中查找和索引值,然后替换 rawData 中的值。

      replaceID <- function(to,from,mergeBy,values){
        x <- match(from[,mergeBy],to[,mergeBy])
        to[,values][x] <- as.character(from[,values])
        return(to)
      }
      > rawData <- replaceID(rawData,Halictidae,"beeID","family")
      > rawData
         beeID     family
      1      1       <NA>
      2      2 Halictidae
      3      3       <NA>
      4      4       <NA>
      5      5 Halictidae
      6      6       <NA>
      7      7       <NA>
      8      8 Halictidae
      9      9       <NA>
      10    10       <NA>
      11    11 Halictidae
      12    12       <NA>
      13    13       <NA>
      14    14 Halictidae
      15    15       <NA>
      16    16       <NA>
      17    17 Halictidae
      18    18       <NA>
      19    19       <NA>
      20    20 Halictidae
      

      【讨论】:

      • 这是完美的,它完全符合我最初的设想。感谢您的帮助!干杯,扎克
      【解决方案3】:

      另一种选择是在包plyr 中使用?join

          library(plyr)
      #Adding family ahead of time was unnecessary so I'll remove it alongside the join.
      join(rawData, speciesInfo, by = "beeID", type = "left")[,-2]
         beeID     family
      1      1 Andrenidae
      2      2       <NA>
      3      3       <NA>
      4      4 Andrenidae
      5      5       <NA>
      6      6       <NA>
      7      7 Andrenidae
      8      8       <NA>
      9      9       <NA>
      10    10 Andrenidae
      11    11       <NA>
      12    12       <NA>
      13    13 Andrenidae
      14    14       <NA>
      15    15       <NA>
      16    16 Andrenidae
      17    17       <NA>
      18    18       <NA>
      19    19 Andrenidae
      20    20       <NA>
      

      更新

      # If you anticipate adding new species over time, 
      # simply rbind those into a single reference data.frame to merge with your rawData. 
      # Like so:
      library(plyr)
      rawData <- join(rawData, rbind(Andrenidae, Halictidae), by = "beeID", type = "left")
      
      # To keep you code clean, you could do this step ahead of time
      species_list <- rbind(Andrenidae, Halictidae)
      rawData <- join(rawData, species_list, by = "beeID", type = "left")
      

      【讨论】:

      • 我不确定如何在回复中包含代码,所以我编辑了我的原始问题并添加了一个后续问题。我一直是个潜伏者,所以我还没有掌握贡献的窍门。再次感谢您的任何帮助!
      • 很高兴您编辑了您的问题(这就是 SO 的工作方式,即根据答案澄清和改进您的问题)。编辑后的答案应该解决您的新问题。如果您的数据集变得更大,则有更强大的解决方案。
      【解决方案4】:

      您可以使用merge 函数,例如:

      rawData <- data.frame(beeID=c(1:20),family=rep(NA,20))
      speciesInfo <- data.frame(beeID=seq(1,20,3),
                                family=c(rep('Halictidae',4), rep("Andrenidae",3)))
      
      merged <- merge(x=rawData,y=speciesInfo,by='beeID',all.x=T,all.y=F)
      merged$family.x <- NULL # remove the family.x column
      names(merged) <- c('beeID','family') # rename the columns
      

      注意

      不必用family列初始化rawData
      合并功能将自动添加它,例如:

      rawData <- data.frame(beeID=c(1:20))
      speciesInfo <- data.frame(beeID=seq(1,20,3),
                                family=c(rep('Halictidae',4), rep("Andrenidae",3)))
      
      merged <- merge(x=rawData,y=speciesInfo,by='beeID',all.x=T,all.y=F)
      
      > merged
         beeID     family
      1      1 Halictidae
      2      2       <NA>
      3      3       <NA>
      4      4 Halictidae
      5      5       <NA>
      6      6       <NA>
      7      7 Halictidae
      8      8       <NA>
      9      9       <NA>
      10    10 Halictidae
      11    11       <NA>
      12    12       <NA>
      13    13 Andrenidae
      14    14       <NA>
      15    15       <NA>
      16    16 Andrenidae
      17    17       <NA>
      18    18       <NA>
      19    19 Andrenidae
      20    20       <NA>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-31
        • 2018-12-29
        • 1970-01-01
        • 2018-12-27
        相关资源
        最近更新 更多