R列映射

问题描述 投票:0回答:3

如何将一个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
r dataframe mapping
3个回答
0
投票

最初,它看起来像一个微不足道的问题,但事实并非如此。这种方法的工作方式如下: 1.我们使用unliststrsplit将位置字符串转换为矢量。 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

1
投票

使用的解决方案。首先,请通过设置col2将您的stringsAsFactors = FALSE转换为角色,因为这更容易使用。

我们可以使用str_extract提取匹配的国家/地区名称,然后使用col2mutate创建一个新的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)

1
投票

如果您正在寻找这些国家,并且他们来到城市之后,那么您可以做这样的事情。

  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
© www.soinside.com 2019 - 2024. All rights reserved.