在大多数列具有多个值的地方从长到宽重塑

Reshape long to wide where most columns have multiple values

我有如下数据:

IDnum   zipcode   City          County   State
10011   36006     Billingsley   Autauga  AL 
10011   36022     Deatsville    Autauga  AL
10011   36051     Marbury       Autauga  AL
10011   36051     Prattville    Autauga  AL
10011   36066     Prattville    Autauga  AL
10011   36067     Verbena       Autauga  AL
10011   36091     Selma         Autauga  AL
10011   36703     Jones         Autauga  AL
10011   36749     Plantersville Autauga  AL
10011   36758     Uriah         Autauga  AL
10011   36480     Atmore        Autauga  AL
10011   36502     Bon Secour    Autauga  AL

我有一个邮政编码列表、它们包含的城市以及它们所在的 counties/states。IDnum = 县和州的组合数值。列表是你现在看到的格式,我需要将它从长到宽/垂直到水平,其中 IDnum 变量成为唯一标识符,所有其他可能的值组合成为宽变量。

IDnum  zip1   city1        county1  state1  zip2   city2       county2
10011  36006  Billingsley  Autauga  AL      36022  Deatsville  Autauga

这只是数据集的样本,它涵盖了美国的每个邮编并包含更多变量。我见过与此类似的其他问题和答案,但几乎每一列都没有多个值。

SPSS 和 STATA 中的命令会以这种方式重塑数据,在 SPSS 中我可以 运行 一个 Restructure/Cases 到 Vars 命令,将我初始数据集中的 11 个变量变成大约 1750,b/c 一个县有超过 290 个 zips,它复制了大多数其他变量 290 多次。这会产生很多空白,但我需要将其重新整形为一个非常长的水平文件。

我查看了 reshape 和 reshape2,但被 'default to length' 错误消息挂断了。我确实得到了 melt/dcast 来排序,但这会创建一个变量,它是所有值的列表,而不是为每个值创建变量。

melted_dupes <- melt(zip_code_list_dupes, id.vars= c("IDnum"))
HRZ_dupes <- dcast(melted_dupes, IDnum ~ variable, fun.aggregate = list) 

我已经尝试过 tidyr 和 dplyr,但在语法上迷失了方向。有点惊讶没有类似于其他包中内置命令的数据命令,让我假设有,但我还没有弄明白。

感谢任何帮助。

可能有更有效的方法,但请尝试以下方法。 我使用了我自己的(示例)数据集,与您的数据集非常相似。 运行 逐步了解其工作原理,因为您必须修改代码中的某些内容。

library(dplyr)
library(tidyr)

# get example data
dt = data.frame(id = c(1,1,1,2,2),
zipcode = c(4,5,6,7,8),
city = c("A","B","C","A","C"),
county = c("A","B","C","A","C"),
state = c("A","B","C","A","C"))

dt

#   id zipcode city county state
# 1  1       4    A      A     A
# 2  1       5    B      B     B
# 3  1       6    C      C     C
# 4  2       7    A      A     A
# 5  2       8    C      C     C


# get maximum number of rows for a single id
# this will help you get the wide format
max_num_rows = max((dt %>% count(id))$n)

# get names of columns to reshape
col_names = names(dt)[-1]

dt %>% 
group_by(id) %>% 
mutate(nrow = paste0("row",row_number())) %>%
unite_("V",col_names) %>%
spread(nrow, V) %>%
unite("z",matches("row")) %>%
separate(z, paste0(col_names, sort(rep(1:max_num_rows, ncol(dt)-1))), convert=T) %>%
ungroup()

# # A tibble: 2 × 13
#      id zipcode1 city1 county1 state1 zipcode2 city2 county2 state2 zipcode3 city3 county3 state3
# * <dbl>    <int> <chr>   <chr>  <chr>    <int> <chr>   <chr>  <chr>    <int> <chr>   <chr>  <chr>
# 1     1        4     A       A      A        5     B       B      B        6     C       C      C
# 2     2        7     A       A      A        8     C       C      C       NA  <NA>    <NA>   <NA>

您可以在按 IDnum 添加连续计数后使用基本函数 reshape 执行此操作。假设您的数据存储在名为 df:

data.frame
df2 <- within(df, count <- ave(rep(1,nrow(df)),df$IDnum,FUN=cumsum)) 

提供名为 "time" 的连续计数的新列。现在我们可以 reshape 到宽格式

reshape(df2,direction="wide",idvar="IDnum",timevar="count") 
  IDnum zipcode.1      City.1 County.1 State.1 zipcode.2     City.2 County.2 State.2 zipcode.3  City.3 County.3 State.3 zipcode.4     City.4 County.4 State.4
1 10011     36006 Billingsley  Autauga      AL     36022 Deatsville  Autauga      AL     36051 Marbury  Autauga      AL     36051 Prattville  Autauga      AL

(输出被截断,一直到 zipcode.12,等等)