我在数据框变量中有数百个地址,需要从中提取邮政编码。一些地址包含多个城市,每个城市都有一个邮政编码。这是一个提取邮政编码的数据框和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}")
答案 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