首页 > 解决方案 > 铸造(传播)多列字符向量的优雅解决方案

问题描述

我想将带有联系信息的数据框转换为一个城市列表,其中类似信息(例如电话号码)出现在多个列中。

我试过同时使用reshape2::dcast()tidyr::spread(),但都不能解决我的问题。我还检查了堆栈溢出的其他帖子,例如

多列展开

尚未找到可行的解决方案。在我看来,这些问题应该相当简单(并且可以通过 spread 或 dcast 解决)。

tmp <- tibble(municipality = c("M1", "M2"), 
       name1 = c("n1", "n2"), name2 = c("n3", "n4"), name3 = c(NA, "n5"), # placeholder names
       phone1 = c("p1", "p2"), phone2 = c("p3", "p4"), phone3 = c(NA, "p5")) # placeholder phone numbers

#solution 1
tmp %>% gather("colname", "value", -municipality) %>% 
  filter(municipality == "M1") %>% #too simplify, should be replaced with group_by(municipality)
  na.omit() %>% mutate(colname = str_replace(colname, "\\d", replacement = "")) %>% 
  spread(., key = "colname", value = "value")

#Solution 2
tmp %>% gather("colname", "value", -municipality) %>% 
  filter(municipality == "M1") %>% # same as above
  na.omit() %>% mutate(colname = str_replace(colname, "\\d", replacement = "")) %>% 
  dcast(municipality + value ~colname)


解决方案 1 导致以下错误: 错误:每行输出必须由唯一的键组合标识。

解决方案 2 产生以下数据框(这是所需的结果,但需要折叠):

  municipality value name phone
1           M1    n1   n1  <NA>
2           M1    n3   n3  <NA>
3           M1    p1 <NA>    p1
4           M1    p3 <NA>    p3

标签: rtidyrspreaddcast

解决方案


你在找吗?

library(dplyr)
library(tidyr)

tmp %>%
  gather(key, value, -municipality, na.rm = TRUE) %>%
  mutate(key = gsub("\\d+", "", key)) %>%
  group_by(municipality, key) %>%
  mutate(row = row_number()) %>%
  spread(key, value) %>%
  select(-row)

# municipality name  phone
# <chr>        <chr> <chr>
#1 M1           n1    p1   
#2 M1           n3    p3   
#3 M2           n2    p2   
#4 M2           n4    p4   
#5 M2           n5    p5  

我们可以使用gather以长格式删除NA值的数据。从各个列名中删除数字,使它们共享相同key,创建列group_by municipality并将数据转换keyspread宽格式。


推荐阅读