使用R,当字符串提取在数据框中创建列表元素时,如何为列表中的每个项添加行?

时间:2014-10-12 12:25:54

标签: regex r qdapregex

我在数据框变量中有数百个地址,需要从中提取邮政编码。一些地址包含多个城市,每个城市都有一个邮政编码。这是一个提取邮政编码的数据框和R代码的模拟示例。

require(qdapRegex)
require(stringr)

df <- data.frame(address = c("Walnut; 94596, Ontario, 91761, Beach, CA 90071", "Irvine Cal 92164"), var2 = "text")
df$zip.Rinker <- sapply(df$address, FUN = rm_zip, extract=TRUE) 

来自Tyler Rinker的rm_zip软件包的qdapRegex函数会提取所有邮政编码,如果有多个邮政编码,则将其列入清单。

> df
                                         address var2          zip.Rinker
1 Walnut; 94596, Ontario, 91761, Beach, CA 90071 text 94596, 91761, 90071
2                               Irvine Cal 92164 text               92164

如何为zip.Rinker下第1行的每个邮政编码创建一个新行?像下面这样的东西是理想的。请注意,会有数十个地址有多个邮政编码,因此我希望找到一个不需要手动步骤的解决方案。

                                         address var2          zip.Rinker
1 Walnut; 94596, Ontario, 91761, Beach, CA 90071 text               94596
2 Walnut; 94596, Ontario, 91761, Beach, CA 90071 text               91761
3 Walnut; 94596, Ontario, 91761, Beach, CA 90071 text               90071
4                               Irvine Cal 92164 text               92164

感谢您的时间。

PS使用stringr,此代码提取邮政编码并提出相同的挑战。

df$zip.stringr <- str_extract_all(string = df$address, pattern = "\\d{5}") 

4 个答案:

答案 0 :(得分:2)

你可以这样做:

data.frame(rep(df$address, sapply(df$zip.Rinker, length)), unlist(df$zip.Rinker)

##   rep.df.address..sapply.df.zip.Rinker..length.. unlist.df.zip.Rinker.
## 1 Walnut; 94596, Ontario, 91761, Beach, CA 90071                 94596
## 2 Walnut; 94596, Ontario, 91761, Beach, CA 90071                 91761
## 3 Walnut; 94596, Ontario, 91761, Beach, CA 90071                 90071
## 4                               Irvine Cal 92164                 92164

但请注意,rm_zip已经过矢量化,并且包装stringi包时非常快。所以不需要sapply。这是一种方法,可以使用qdapTools的{​​{1}}使代码更加精简,该list2df采用已命名的list向量并将其转换为data.frame

library(qdapTools)
list2df(setNames(rm_zip(df$address, extract=TRUE), df$address), "zip", "address")[, 2:1]

##                                          address   zip
## 1 Walnut; 94596, Ontario, 91761, Beach, CA 90071 94596
## 2 Walnut; 94596, Ontario, 91761, Beach, CA 90071 91761
## 3 Walnut; 94596, Ontario, 91761, Beach, CA 90071 90071
## 4                               Irvine Cal 92164 92164

我喜欢嵌套函数的magrittr框架,所以这就是:

library(qdapTools)
library(magrittr)

df$address %>%
    rm_zip(extract=TRUE) %>%
    setNames(df$address) %>%
    list2df("zip", "address") %>%
    `[`(, 2:1)

答案 1 :(得分:1)

以下是使用“data.table”和gregexpr / regmatches的方法:

library(data.table)
as.data.table(df)[, c(.SD, Zips = unlist(list(
  Zips = regmatches(address, gregexpr("\\d{5}", address))))), 
  by = 1:nrow(df)]
#    nrow                                        address var2  Zips
# 1:    1 Walnut; 94596, Ontario, 91761, Beach, CA 90071 text 94596
# 2:    1 Walnut; 94596, Ontario, 91761, Beach, CA 90071 text 91761
# 3:    1 Walnut; 94596, Ontario, 91761, Beach, CA 90071 text 90071
# 4:    2                               Irvine Cal 92164 text 92164

答案 2 :(得分:0)

这是一种仅使用stringi包的方法:

library(stringi)
zip <- stri_extract_all_regex(df$address, "\\d{5}") 
data.frame(address=rep(df$address, sapply(zip, length)), zip=unlist(zip))

##                                          address   zip
## 1 Walnut; 94596, Ontario, 91761, Beach, CA 90071 94596
## 2 Walnut; 94596, Ontario, 91761, Beach, CA 90071 91761
## 3 Walnut; 94596, Ontario, 91761, Beach, CA 90071 90071
## 4                               Irvine Cal 92164 92164

答案 3 :(得分:0)

另一种方法,这个方法只使用基数R和hwnd的正则表达式来提取邮政编码Remove US zip codes from a string: Regex

match <- gregexpr('(?<!\\d)\\d{5}(?:[ -]\\d{4})?\\b', df$address, perl=T)
zips <- regmatches(df$address,match)
nn <- rep(1:length(match),sapply(zips,length))
data.frame(df[nn,], zip=unlist(zips))

                                          address var2   zip
1   Walnut; 94596, Ontario, 91761, Beach, CA 90071 text 94596
1.1 Walnut; 94596, Ontario, 91761, Beach, CA 90071 text 91761
1.2 Walnut; 94596, Ontario, 91761, Beach, CA 90071 text 90071
2                                 Irvine Cal 92164 text 92164