在r中改进嵌套的ifelse语句

时间:2014-12-09 20:31:10

标签: r

我有超过10k的地址信息,在字符向量中看起来像" XXX街道,城市,州,美国" 我想按状态对它们进行分组,所以我使用嵌套的ifelse来获取地址date.frame,其中包含两个变量add_info和state。

library(stringr)
for (i in nrow(address){
    ifelse(str_detect(address, 'Alabama'), address[i,state]='Alabama',
    ifelse(str_detect(address, 'Alaska'), address[i,state]='Alaska',
    ifelse(str_detect(address, 'Arizona'), address[i,state]='Arizona',
    ...
    ifelse(str_detect(address, 'Wyoming'), address[i,state]='Wyoming', address[i,state]=NA)...)
}

当然,这是非常低效的,但我不知道如何重写这个嵌套的ifelse。有什么想法吗?

4 个答案:

答案 0 :(得分:0)

有几种方法。

首先我们需要一些样本数据。

# some sample data
set.seed(123)
dat <- data.frame(addr=sprintf('123 street, Townville, %s, US',
                               sample(state.name, 25, replace=T)),
                  stringsAsFactors=F)

如果您的数据非常规则:

# the easy way, split on commas:
matrix(unlist(strsplit(dat$addr, ',')), ncol=4, byrow=T)

方法2,使用grep搜索值。即使不同行中没有逗号或不同的逗号,这也可以工作。 (只要状态总是以相同的方式拼写)

# get a list of state name matches; need to match ', state name,' otherwise
# West Virginia counts as Virginia...
matches <- sapply(paste0(', ', state.name, ','), grep, dat$addr)

# now pair up the state name with the row it matches to
state_df <- data.frame(state=rep(state.name, sapply(matches, length)),
                       row=unname(unlist(matches)),
                       stringsAsFactors=F)

# reorder based on position in original data.frame, and there you go!
dat$state <- state_df[order(state_df$row), 'state']

答案 1 :(得分:0)

有很多方法可以解决这个问题。假设您的地址字符串始终只包含一个美国州的完整拼写,这是一种方法。

library(stringr)

# Get a list of all states
state.list = scan(text = "Alabama, Alaska, Arizona, Arkansas, California, Colorado, Connecticut, Delaware, Florida, Georgia, Hawaii, Idaho, Illinois, Indiana, Iowa, Kansas, Kentucky, Louisiana, Maine, Maryland, Massachusetts, Michigan, Minnesota, Mississippi, Missouri, Montana, Nebraska, Nevada, New Hampshire, New Jersey, New Mexico, New York, North Carolina, North Dakota, Ohio, Oklahoma, Oregon, Pennsylvania, Rhode Island, South Carolina, South Dakota, Tennessee, Texas, Utah, Vermont, Virginia, Washington, West Virginia, Wisconsin, Wyoming", what = "",  sep = ",", strip.white = T)

# Extract state from vector address using library(stringr)
state = unlist(sapply(address, function(x) state.list[str_detect(x, state.list)]))

# Generate fake data to test
fake.address = paste0(replicate(10, paste(sample(c(0:9, LETTERS), 10, replace=TRUE), collapse="")), 
                      sample(state.list, 20, rep = T), 
                      replicate(10, paste(sample(c(0:9, LETTERS), 10, replace=TRUE), collapse="")))

# Test using fake address
unlist(sapply(fake.address, function(x) state.list[str_detect(x, state.list)]))

虚假地址输出

      O4H8V0NYEHColoradoA5K5XK35LX           44NDPQVMZ8UtahMY0I4M3086        LJ0LJW8BOBFloridaP5H2QW8B81     521IHHC1MFCaliforniaG7QTYCJRO5 
                        "Colorado"                             "Utah"                          "Florida"                       "California" 
  YESTB7R6EPRhode IslandXEEGD4GEY3         5OHN2BR29HKansasCOKR9DY1WJ     4UXNJQW0QKNew MexicoH9GVQR3ZFY          5SYELTKO5HTexas3ONM1HU1VB 
                    "Rhode Island"                           "Kansas"                       "New Mexico"                            "Texas" 
    Z8MKKL7K1RWashingtonGEBS7LJUU0        WPRSQEI2CNIndiana141S0Z1M2E   O4H8V0NYEHNorth DakotaA5K5XK35LX  44NDPQVMZ8New HampshireMY0I4M3086 
                      "Washington"                          "Indiana"                     "North Dakota"                    "New Hampshire" 
LJ0LJW8BOBWest VirginiaP5H2QW8B811 LJ0LJW8BOBWest VirginiaP5H2QW8B812     521IHHC1MFNew JerseyG7QTYCJRO5      YESTB7R6EPWisconsinXEEGD4GEY3 
                        "Virginia"                    "West Virginia"                       "New Jersey"                        "Wisconsin" 
        5OHN2BR29HOregonCOKR9DY1WJ           4UXNJQW0QKOhioH9GVQR3ZFY   5SYELTKO5HRhode Island3ONM1HU1VB       Z8MKKL7K1ROklahomaGEBS7LJUU0 
                          "Oregon"                             "Ohio"                     "Rhode Island"                         "Oklahoma" 
          WPRSQEI2CNIowa141S0Z1M2E 
                            "Iowa" 

编辑:使用基于agrep()的以下函数进行模糊匹配。应该处理轻微的拼写错误。您可能需要编辑注释以复制代码。该代码包含一个index-assign [&lt; - 操作符,在功能上调用,因此显示在此处有故障。

unlist(sapply(fake.address, function(x) state.list[并[d - ((L<-as.logical(sapply(state.list, function(s) agrep(s, x)*1))),is.na(L),F)]))

答案 2 :(得分:0)

假设您的格式一致(感谢Joran上面的评论),您只需使用strsplit进行解析,然后使用data.frame

address1<-"410 West Street, Small Town, MN, US"
address2<-"5844 Green Street, Foo Town, NY, US"
address3<-"875 Cardinal Lane, Placeville, CA, US"

vector<-c(address1,address2,address3)
df<-t(data.frame(strsplit(vector,", "))
colnames(df)<-c("Number","City","State","Country")
rownames(df)<-NULL

df

产生:

     Number              City         State Country
[1,] "410 West Street"   "Small Town" "MN"  "US"   
[2,] "5844 Green Street" "Foo Town"   "NY"  "US"   
[3,] "875 Cardinal Lane" "Placeville" "CA"  "US"   

答案 3 :(得分:0)

这似乎在我的测试中起作用:

 just.ST <- gsub( paste0(".+(", paste(state.name,collapse="|"), ").+$"),
        "\\1", address)

正如评论中所述并在其他答案中说明的那样,state.name默认情况下应该可用。它确实有缺点,如果不匹配,它返回整个字符串,但你可以使用:

  is.na(just.ST) <- nchar(just.ST) > max(nchar(state.name))