【问题标题】:R column mappingR列映射
【发布时间】:2018-03-04 13:44:10
【问题描述】:

如何将一个 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

【问题讨论】:

  • 欢迎来到 Stack Overflow。你的问题是一个好的开始,但如果你给出一些你尝试过的例子,它会得到改进。还可以尝试将您的示例数据转换为有人可以复制并粘贴到他们的 R 中的格式。
  • 感谢您的建议。实际上我正在处理庞大的数据集,并且我已经粘贴了原始数据集中的一些数据。目前没有任何想法来获得所需的输出。我有很多类似的列要映射。我只是想要一个提示怎么做?
  • 只需获取您已有的样本位并将它们分配给向量。根据您所说,您需要搜索匹配子字符串或连接子字符串。
  • 抱歉,我没有得到你。如果我将我的数据样本发布到 GitHub 并附上问题陈述,你能帮我吗?
  • 您知道@stuski 是如何帮助您的吗?现在解释一下您在搜索 SO 和 google 寻找答案时发现和尝试的内容。

标签: r dataframe mapping


【解决方案1】:

最初,这看起来像是一个微不足道的问题,但事实并非如此。这种方法的工作原理如下:

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

【讨论】:

  • 我建议 df2 实际上是一个字符向量。不需要它是一个数据框。
  • 即使我也这么认为。但是,问题说有2个数据框。虽然,你是对的。
【解决方案2】:

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

我们可以使用str_extract提取匹配的国家名称,然后用mutateifelse创建一个新的col2

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)

【讨论】:

  • @Onyambu 谢谢。如果col2 中有多个国家/地区名称,我认为 OP 需要小心。希望所有行的模式都是一致的。
【解决方案3】:

如果您正在寻找国家/地区,并且它们紧随城市,那么您可以执行类似的操作。

  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

【讨论】:

    猜你喜欢
    • 2023-03-10
    • 1970-01-01
    • 2017-10-17
    • 2019-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-19
    相关资源
    最近更新 更多