【问题标题】:Simplify replacing vector elements according to criteria using an apply function使用 apply 函数根据标准简化替换向量元素
【发布时间】:2015-07-15 01:25:48
【问题描述】:

我有一个数据集,其中包含一个名为 Region 的变量,它代表澳大利亚的不同地区。以下是来自数据的 25 行:

> head(sample.2013$Region, n = 25)
 [1] QLD major urban - capital city   VIC rural                        NSW regional - low urbanisation 
 [4] SA regional - low urbanisation   NSW regional - low urbanisation  Tas rural                       
 [7] ACT major urban - capital city   QLD rural                        ACT major urban - capital city  
[10] NT regional - low urbanisation   NSW other                        QLD rural                       
[13] ACT major urban - capital city   VIC regional - high urbanisation Tas rural                       
[16] QLD major urban - capital city   Tas rural                        VIC regional - high urbanisation
[19] QLD rural                        Tas rural                        VIC rural                       
[22] QLD other urban                  Tas rural                        VIC rural                       
[25] ACT major urban - capital city
36 Levels: ACT major urban - capital city NSW major urban - capital city NSW other urban ... ?

朴素的解决方案

我需要根据此列中的变量创建另一个名为 state 的变量。目前我只是使用蛮力方法来创建一个像这样的新向量:

add_states <- function(sample.2013) {
    # Add states from the region variable
    sample.2013$State[grepl('NSW', sample.2013$Region) == TRUE] <- 'NSW'
    sample.2013$State[grepl('VIC', sample.2013$Region) == TRUE] <- 'VIC'
    sample.2013$State[grepl('QLD', sample.2013$Region) == TRUE] <- 'QLD'
    sample.2013$State[grepl('WA', sample.2013$Region) == TRUE] <- 'WA'
    sample.2013$State[grepl('SA', sample.2013$Region) == TRUE] <- 'SA'
    sample.2013$State[grepl('Tas', sample.2013$Region) == TRUE] <- 'TAS'
    sample.2013$State[grepl('TAS', sample.2013$Region) == TRUE] <- 'TAS'
    sample.2013$State[grepl('ACT', sample.2013$Region) == TRUE] <- 'ACT'
    sample.2013$State[grepl('NT', sample.2013$Region) == TRUE] <- 'NT'
    return(sample.2013)
}

这很好用,但是很难测试并且很脆弱。例如,我现在知道我可以将ignore-case 传递给grepl,这样就不需要两个塔斯马尼亚案例了。

For 循环

我已经能够用 for 循环和这样的函数替换上述“天真的”方法:

add_state <- function(input, output, state) {
    # Change the variable y in place, prevents duplication
    output <- replace(output, grepl(state, input, ignore.case = TRUE), state)
    output
}

state_codes <- c('NSW', 'VIC', 'QLD', 'WA', 'SA', 'TAS', 'ACT', 'NT')
test_vector <- head(sample.2013$Region, n = 500)

y = vector('character', length = length(test_vector))

for (i in 1:length(state_codes)) {
    y <- add_state(test_vector, y, state_codes[i])
}

    table(y)
y
    ACT NSW  NT QLD  SA TAS VIC  WA 
 14  99  50  42  49  98  92  45  11 

但这也很冗长,for 循环不是惯用的 R。我无法用 apply 函数替换这段代码并让它替换向量中的值,而不是创建一堆其他向量。

应用

这是我使用 lapply 管理过的最好的:

add_state3 <- function(x, state) {
    x <- replace(x, grepl(state, x, ignore.case = TRUE), state)
    x
}

test_vector_short <- c("NSW 1", "NSW 2", "Vic", "Goo")

> output <- lapply(state_codes, add_state3, x = test_vector_short)
> output
[[1]]
[1] "NSW" "NSW" "Vic" "Goo"

[[2]]
[1] "NSW 1" "NSW 2" "VIC"   "Goo"  

[[3]]
[1] "NSW 1" "NSW 2" "Vic"   "Goo"  

[[4]]
[1] "NSW 1" "NSW 2" "Vic"   "Goo"  

[[5]]
[1] "NSW 1" "NSW 2" "Vic"   "Goo"  

[[6]]
[1] "NSW 1" "NSW 2" "Vic"   "Goo"  

[[7]]
[1] "NSW 1" "NSW 2" "Vic"   "Goo"  

[[8]]
[1] "NSW 1" "NSW 2" "Vic"   "Goo"  

该函数有效,它获取状态代码的每个实例并将其传递给 add_state3 函数,但它创建一个包含 8 个元素的列表,而不是替换元素。

问题

对冗长的序言感到抱歉,但本质上我的问题是如何使用应用函数根据某些标准就地更改向量的元素?

【问题讨论】:

  • 次要观点:你不需要grepl(...) == TRUE 中的== TRUE,因为grepl() 已经返回了一个逻辑向量(正如测试本身所表明的那样)。
  • @bgoldst 是的,我在发布后注意到了这一点。干杯。

标签: r


【解决方案1】:

您可以使用gsub 来组合您的搜索和替换,例如gsub('^.*\\bNT\\b.*$', 'NT') 将替换所有匹配的 NT 字符串(\\b 以避免“品脱”匹配“NT”)。

如果你让你的正则表达式类似于'^.*\\b(NSW|NT|QLD|...)\b.*',然后你用\\1(捕获的匹配)替换,你可以这样做:

state.regex <- sprintf('^.*\\b(%s)\\b.*$', paste(state_codes, collapse='|'))
# "^.*\\b(NSW|VIC|QLD|WA|SA|TAS|ACT|NT)\\b.*$"
gsub(state.regex, '\\1', test_vector_short, ignore.case=T)
# [1] "NSW" "NSW" "Vic" "Goo"

这取决于这样一个事实,即每当您找到匹配项时,您都希望将整个匹配项替换为匹配项,并且匹配项(状态代码)可以压缩为一个正则表达式。

否则,我相信您必须像以前那样循环(因为您需要进行替换,然后在更新的向量上进行替换)。

【讨论】:

    【解决方案2】:

    似乎有STATECODE other stuff 的模式,所以您可以只使用strsplit 并获取第一个元素

    使用test:

    test <- c(
      "QLD major urban - capital city",
      "Vic rural",
      "NSW regional - low urbanisation", 
      "SA regional - low urbanisation",
      "NSW regional - low urbanisation",
      "guff and goo"
    )
    
    result <- toupper(sapply(strsplit(test," "),`[`,1))
    replace(result, !result %in% state_codes, NA)
    #[1] "QLD" "VIC" "NSW" "SA"  "NSW" NA   
    

    【讨论】:

      【解决方案3】:

      由于每个Region 的第一个字是状态码,您可以去掉其余部分并将结果用作新的state 变量:

      sample.2013 <- data.frame(Region=c('QLD major urban - capital city','VIC rural','NSW regional - low urbanisation','SA regional - low urbanisation','NSW regional - low urbanisation  Tas rural','ACT major urban - capital city','QLD rural','ACT major urban - capital city','NT regional - low urbanisation','NSW other','QLD rural','ACT major urban - capital city','VIC regional - high urbanisation Tas rural','QLD major urban - capital city','Tas rural','VIC regional - high urbanisation','QLD rural','Tas rural','VIC rural','QLD other urban','Tas rural','VIC rural','ACT major urban - capital city'));
      sample.2013$state <- toupper(sub(' .*','',sample.2013$Region));
      sample.2013;
      ##                                        Region state
      ## 1              QLD major urban - capital city   QLD
      ## 2                                   VIC rural   VIC
      ## 3             NSW regional - low urbanisation   NSW
      ## 4              SA regional - low urbanisation    SA
      ## 5  NSW regional - low urbanisation  Tas rural   NSW
      ## 6              ACT major urban - capital city   ACT
      ## 7                                   QLD rural   QLD
      ## 8              ACT major urban - capital city   ACT
      ## 9              NT regional - low urbanisation    NT
      ## 10                                  NSW other   NSW
      ## 11                                  QLD rural   QLD
      ## 12             ACT major urban - capital city   ACT
      ## 13 VIC regional - high urbanisation Tas rural   VIC
      ## 14             QLD major urban - capital city   QLD
      ## 15                                  Tas rural   TAS
      ## 16           VIC regional - high urbanisation   VIC
      ## 17                                  QLD rural   QLD
      ## 18                                  Tas rural   TAS
      ## 19                                  VIC rural   VIC
      ## 20                            QLD other urban   QLD
      ## 21                                  Tas rural   TAS
      ## 22                                  VIC rural   VIC
      ## 23             ACT major urban - capital city   ACT
      

      【讨论】:

        猜你喜欢
        • 2018-11-21
        • 2016-08-16
        • 2011-11-11
        • 2017-12-08
        • 1970-01-01
        • 2020-03-08
        • 1970-01-01
        • 1970-01-01
        • 2018-10-30
        相关资源
        最近更新 更多