如何将一个CSV文件的列映射到R中另一个CSV文件的列。如果两个文件都在相同的数据类型中。例如,数据框A的第一列包含一些带有国家/地区名称的文本。而第二个数据框B的列包含所有国家的标准列表。现在我必须将第一个数据框的所有行映射到标准国家列。
例如,数据帧A的列(位置)包括10000行这样的数据
Sydney, Australia
Aarhus C, Central Region, Denmark
Auckland, New Zealand
Mumbai Area, India
Singapore
df1 <- data.frame(col1 = 1:5, col2=c("Sydney, Australia", "Aarhus C, Central Region, Denmark", "Auckland, New Zealand", "Mumbai Area, India", "Singapore"))
现在我有另一列(国家)的数据框B为
India
USA
New Zealand
UK
Singapore
Denmark
China
df2 <- data.frame(col1=1:7, col2=c("India", "USA", "New Zealand", "UK", "Singapore", "Denmark", "China"))
如果位置列与国家列匹配,那么我想用国家名称替换该位置,否则它将保持原样。样本输出为
Sydney, Australia
Denmark
New Zealand
India
Singapore
最初,它看起来像一个微不足道的问题,但事实并非如此。这种方法的工作方式如下:
1.我们使用unlist
,strsplit
将位置字符串转换为矢量。
2.然后我们检查向量中的任何字符串是否在国家/地区列中可用。如果可用,我们将国家名称存储在res
中,如果没有,我们存储notfound
。
2.最后,我们检查res是否包含国家/地区名称。
df1 <- data.frame(location = c('Sydney, Australia',
'Aarhus C, Central Region, Denmark',
'Auckland, New Zealand',
'Mumbai Area, India',
'Singapore'),stringsAsFactors = F)
df2 <- data.frame(country = c('India',
'USA',
'New Zealand',
'UK',
'Singapore',
'Denmark',
'China'),stringsAsFactors = F)
get_values <- function(i)
{
val <- unlist(strsplit(i, split = ','))
val <- sapply(val, str_trim)
res <- c()
for(j in val)
{
if(j %in% df2$country) res <- append(res, j)
else res <- append(res, 'notfound')
}
if(all(res == 'notfound')) return (i)
else return (res[res!='notfound'])
}
df1$location2 <- sapply(df1$location, get_values)
location location2
1 Sydney, Australia Sydney, Australia
2 Aarhus C, Central Region, Denmark Denmark
3 Auckland, New Zealand New Zealand
4 Mumbai Area, India India
5 Singapore Singapore
使用tidyverse的解决方案。首先,请通过设置col2
将您的stringsAsFactors = FALSE
转换为角色,因为这更容易使用。
我们可以使用str_extract
提取匹配的国家/地区名称,然后使用col2
和mutate
创建一个新的ifelse
。
df3 <- df1 %>%
mutate(Country = str_extract(col2, paste0(df2$col2, collapse = "|")),
col2 = ifelse(is.na(Country), col2, Country)) %>%
select(-Country)
df3
# col1 col2
# 1 1 Sydney, Australia
# 2 2 Denmark
# 3 3 New Zealand
# 4 4 India
# 5 5 Singapore
我们也可以从df1
开始,使用separate_rows
来分隔国家名称。之后,使用semi_join
检查国家名称是否在df2
。最后,我们可以按行将数据框与原始df1
组合,然后在col1
中为每个id过滤第一个。 df3
是最终输出。
library(tidyverse)
df3 <- df1 %>%
separate_rows(col2, sep = ", ") %>%
semi_join(df2, by = "col2") %>%
bind_rows(df1) %>%
group_by(col1) %>%
slice(1) %>%
ungroup() %>%
arrange(col1)
df3
# # A tibble: 5 x 2
# col1 col2
# <int> <chr>
# 1 1 Sydney, Australia
# 2 2 Denmark
# 3 3 New Zealand
# 4 4 India
# 5 5 Singapore
数据
df1 <- data.frame(col1 = 1:5,
col2=c("Sydney, Australia", "Aarhus C, Central Region, Denmark", "Auckland, New Zealand", "Mumbai Area, India", "Singapore"),
stringsAsFactors = FALSE)
df2 <- data.frame(col1=1:7,
col2=c("India", "USA", "New Zealand", "UK", "Singapore", "Denmark", "China"),
stringsAsFactors = FALSE)
如果您正在寻找这些国家,并且他们来到城市之后,那么您可以做这样的事情。
transform(df1,col3= sub(paste0(".*,\\s*(",paste0(df2$col2,collapse="|"),")"),"\\1",col2))
col1 col2 col3
1 1 Sydney, Australia Sydney, Australia
2 2 Aarhus C, Central Region, Denmark Denmark
3 3 Auckland, New Zealand New Zealand
4 4 Mumbai Area, India India
5 5 Singapore Singapore
分解:
> A=sub(".*,\\s(.*)","\\1",df1$col2)
> B=sapply(A,grep,df2$col2,value=T)
> transform(df1,col3=replace(A,!lengths(B),col2[!lengths(B)]))
col1 col2 col3
1 1 Sydney, Australia Sydney, Australia
2 2 Aarhus C, Central Region, Denmark Denmark
3 3 Auckland, New Zealand New Zealand
4 4 Mumbai Area, India India
5 5 Singapore Singapore