【问题标题】:Creating new numeric variable in R based on specific strings from character variable根据字符变量中的特定字符串在 R 中创建新的数值变量
【发布时间】:2021-11-26 04:11:42
【问题描述】:

我在数据框中有一个字符变量,并希望根据该字符变量中存在的特定字符串在该数据框中创建一个新的数值变量。

我想出了一种方法来做到这一点,但想知道是否有比我这里更快或更优雅的方法。

这是我的解决方案,使用 ifelse 和 substr:

首先,我的字符变量的每个观察值是一系列随机的数字和字母(从 0-9 和 A-Z)。我将在下面创建一个示例变量:

library(stringi)
set.seed(100)
my.df<-data.frame("V1"=sprintf("%s%s%s", stri_rand_strings(10, 5, c('[A-B]','[0-2]')),
    stri_rand_strings(10, 4, c('[0-9]','[A-J]')), stri_rand_strings(10, 1, '[A-Z]')))

在我的实际数据中,如上所述,每个观察的第一个元素可以是数字 0-9 或字母 A-Z 中的任何一个。

现在,我所做的是创建一个新变量 [value],它根据 V1 变量中每个观察值的第一个元素是什么来获取特定值(无模式)。所以,如果第一个元素是字母“A”,我的新变量--V2--中对应观察值(行)的值为 3,如果 V1 变量的第一个元素是“B”,则我的新变量 V2 中的相应观察值是 12,等等。

这就是我选择这样做的方式。这很笨拙,因为我的真实数据需要所有数字 0-9 和所有字母 A-Z 的 ifelse 子句,大约 35 行左右。 这是我的代码:

my.df$value<-ifelse(substr(my.df$V1,1,1)=="A",3,
                    ifelse(substr(my.df$V1,1,1)=="B",12,
                           ifelse(substr(my.df$V1,1,1)=="0",44,
                                           ifelse(substr(my.df$V1,1,1)=="1",6,27))))

这会产生:

        V1 value
'AABAA3122X'     1
'12110FCBCF'     6
'BBAAB5246J'    12
'20112JGEDL'    27
'BBBBA4426X'    12
'02210EDFJK'    44
'ABABB6687N'     1
'20120IAEFD'    27
'ABBBB9905A'     1
'12200HCDHU'     6

有没有办法不用这么多代码来做到这一点?

谢谢!

【问题讨论】:

  • 听起来您可能想要创建一个查找表,其中包含每个字母/数字以及它映射到的 value。然后使用join将对应的value匹配到每个字符串
  • 基于示例,第一个值应该是 3,因为您的条件映射到 3

标签: r string if-statement variables


【解决方案1】:

考虑使用 key/val 数据或命名向量的连接

my.df$value <- with(my.df, setNames(c(3, 12, 44, 6),
          c("A", "B", "0", "1"))[substr(V1, 1, 1)])
my.df$value[is.na(my.df$value)] <- "27"

-输出

> my.df
           V1 value
1  AABAA3122X     3
2  12110FCBCF     6
3  BBAAB5246J    12
4  20112JGEDL    27
5  BBBBA4426X    12
6  02210EDFJK    44
7  ABABB6687N     3
8  20120IAEFD    27
9  ABBBB9905A     3
10 12200HCDHU     6

【讨论】:

    【解决方案2】:

    两种可能的方法基于:Canonical tidyverse method to update some values of a vector from a look-up table

    library(tidyverse)
    library(stringi)
    library(data.table)
    
    set.seed(100)
    my.df <- data.frame("V1" = sprintf("%s%s%s",
                                       stri_rand_strings(10, 5, c('[A-B]','[0-2]')),
                                       stri_rand_strings(10, 4, c('[0-9]','[A-J]')),
                                       stri_rand_strings(10, 1, '[A-Z]')))
    
    df <- my.df %>%
      mutate(Value = substr(V1, 1, 1))
    
    unique(df$Value)
    #> [1] "A" "1" "B" "2" "0"
    lookup <- data.frame(old = c("A", 1, "B", 2, 0),
                         new = c(3, 6, 12, 27, 44))
    
    for (i in seq_len(nrow(lookup))) {
        df$Value[df$Value == lookup$old[i]] = lookup$new[i]
    }
    df
    #>            V1 Value
    #> 1  AABAA3122X     3
    #> 2  12110FCBCF     6
    #> 3  BBAAB5246J    12
    #> 4  20112JGEDL    27
    #> 5  BBBBA4426X    12
    #> 6  02210EDFJK    44
    #> 7  ABABB6687N     3
    #> 8  20120IAEFD    27
    #> 9  ABBBB9905A     3
    #> 10 12200HCDHU     6
    
    
    # data.table method (fastest but doesn't retain original order of V1)
    df <- my.df %>%
      mutate(Value = substr(V1, 1, 1))
    
    setDT(df)
    setDT(lookup)
    setkey(df, Value)
    setkey(lookup, old)
    
    df[lookup, Value:=new, on=.(Value=old)]
    df
    #>             V1 Value
    #>  1: 02210EDFJK    44
    #>  2: 12110FCBCF     6
    #>  3: 12200HCDHU     6
    #>  4: 20112JGEDL    27
    #>  5: 20120IAEFD    27
    #>  6: AABAA3122X     3
    #>  7: ABABB6687N     3
    #>  8: ABBBB9905A     3
    #>  9: BBAAB5246J    12
    #> 10: BBBBA4426X    12
    

    reprex package (v2.0.1) 于 2021-10-06 创建

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-28
      • 2020-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多