使用多组度量列将数据框转换为长格式

3
我有一个 R 数据框,使用 XML 包中的 readHTMLTable() 从互联网上爬取。表格如下所示,包含多个人口和年份的变量/列。(请注意,年份在列之间不重复,并且代表人口的唯一标识符。)
        year1   pop1      year2   pop2     year3   pop3     
1                                                        
2       16XX    4675,0    1900    6453,0    1930   9981,2       
3       17XX    4739,3    1901    6553,5    1931   ...      
4       17XX    4834,0    1902    6684,0    1932   
5       180X    4930,0    1903    6818,0    1933        
6       180X    5029,0    1904    6955,0    1934        
7       181X    5129,0    1905    7094,0    1935
8       181X    5231,9    1906    7234,7    1936
9       182X    5297,0    1907    7329,0    1937
10      182X    5362,0    1908    7422,0    1938

我想将数据重新组织成只有两列,一列为年份,一列为人口,格式如下:
        year    pop     
1                                                        
2       16XX    4675,0
3       17XX    4739,3  
4       17XX    4834,0  
5       180X    4930,0
6       180X    5029,0  
7       181X    5129,0
8       181X    5231,9  
9       182X    5297,0
10      182X    5362,0  
11      1900    6453,0
12      1901    6553,5
13      1902    6684,0
...     ...     ...
21      1930    9981,2
22      ... 

变量/列year2year3的值以下附加到year1,相应的人口值也是如此。
我考虑了以下事项:
(1)循环遍历人口和年份列(n>2),并将这些值作为新观测添加到year1和population1中可以工作,但这似乎过于繁琐。
(2)我尝试过下面的融合(melt),但它可能无法处理跨多个列分割的id变量,或者我没有正确实施。
df.melt <- melt(df, id=c("year1", "year2",...)

最后,我考虑将每个年份列作为自己的向量提取出来,并将这些向量附加在一起,如下所示:
year.all <- c(df$year1, df$year2,...)

然而,上述代码对于year.all返回以下结果。
[1]  1  2  3  3  4  4  5  5  6  6  7  8  8  9  9  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24  1  1  2 ...

这不是,而是
[1] 16XX 17XX 17XX 180X 180X 181X 181X 182X 182X 1900 1901 1902...

如果有一种简单明了的方法来完成这个重组,我很愿意学习。非常感谢您的帮助。
3个回答

7

使用 新功能melt 中来自 data.table v1.9.5+:

require(data.table) # v1.9.5+
melt(setDT(df), measure = patterns("^year", "^pop"), value.name = c("year", "pop"))

您可以在这里找到其余的小品文。


非常感谢。函数patterns()是否随着data.table包一起提供?我收到以下错误信息:Error in melt.data.table(setDT(table), measure = patterns("^year", "^population"), : could not find function "patterns",尽管我使用了以下命令install.packages(data.table)library(data.table)require(data.table) - user2489854
啊,它不在v1.9.4中。将进行更新。 - user2489854

6
如果“年份”、“人口”列是交替出现的,我们可以使用 c(TRUE,FALSE)来获取列1、3、5等,使用 c(FALSE,TRUE)来获取2、4、6等,因为它们会循环交替。然后,我们将列unlist并创建一个新的“data.frame”。
 df2 <- data.frame(year=unlist(df1[c(TRUE, FALSE)]), 
                  pop=unlist(df1[c(FALSE, TRUE)]))
 row.names(df2) <- NULL
 head(df2)
 #   year    pop
 #1            
 #2 16XX 4675,0
 #3 17XX 4739,3
 #4 17XX 4834,0
 #5 180X 4930,0
 #6 180X 5029,0

或者另一个选择是:
library(splitstackshape)
merged.stack(transform(df1, id=1:nrow(df1)), var.stubs=c('year', 'pop'), 
        sep='var.stubs')[order(.time_1), 3:4, with=FALSE]

数据

df1 <- structure(list(year1 = c("", "16XX", "17XX", "17XX", "180X", 
"180X", "181X", "181X", "182X", "182X"), pop1 = c("", "4675,0", 
"4739,3", "4834,0", "4930,0", "5029,0", "5129,0", "5231,9", "5297,0", 
"5362,0"), year2 = c(NA, 1900L, 1901L, 1902L, 1903L, 1904L, 1905L, 
1906L, 1907L, 1908L), pop2 = c("", "6453,0", "6553,5", "6684,0", 
"6818,0", "6955,0", "7094,0", "7234,7", "7329,0", "7422,0"), 
year3 = c(NA, 1930L, 1931L, 1932L, 1933L, 1934L, 1935L, 1936L, 
1937L, 1938L), pop3 = c("", "9981,2", "", "", "", "", "", 
"", "", "")), .Names = c("year1", "pop1", "year2", "pop2", 
"year3", "pop3"), class = "data.frame", row.names = c(NA, -10L))

@Jaap,我有“年份”字符列。你能检查一下你是否有“因子”吗? - akrun
@Jaap 我尝试了 df1[c(1,3,5)] <- lapply(df1[c(1,3,5)], factor),仍然得到了预期的结果。 - akrun
当我使用您的数据时,我得到了同样的结果。我认为问题源于在读取数据之前删除了第一行空白行。 - Jaap
1
在这种情况下,我认为仅第一列将是因子,其余的年份列将是数值型的。因此,当它们放在一起时,它们将转换为因子列中的数值级别。 - akrun
1
现在检查了所有变量,不同的“年份”列确实有不同的类。这肯定解释了我这种奇怪的行为。今天又学到了一些东西 :-) - Jaap
显示剩余2条评论

2
另一种选择是使用 split.default 将数据框拆分为数据框列表,然后将它们绑定在一起:
lst <- lapply(split.default(df1, sub('.*(\\d)', '\\1', names(df1))),
              setNames, c('year','pop'))

do.call(rbind, lst)

这将得到期望的结果:

    year     pop
1.1 16XX  4675,0
1.2 17XX  4739,3
1.3 17XX  4834,0
1.4 180X  4930,0
1.5 180X  5029,0
1.6 181X  5129,0
1.7 181X  5231,9
1.8 182X  5297,0
1.9 182X  5362,0
2.1 1900  6453,0
2.2 1901  6553,5
2.3 1902  6684,0
2.4 1903  6818,0
2.5 1904  6955,0
2.6 1905  7094,0
2.7 1906  7234,7
2.8 1907  7329,0
2.9 1908  7422,0
3.1 1930  9981,2
3.2 1931 10583,5
3.3 1932  8671,0
3.4 1933  9118,0
3.5 1934  9625,0
3.6 1935  8097,0
3.7 1936  7984,7
3.8 1937  8729,0
3.9 1938 10462,0

您还可以使用data.table包中的rbindlist进行最后一步操作:

library(data.table)
rbindlist(lst)

使用的数据:

df1 <- structure(list(year1 = c("16XX", "17XX", "17XX", "180X", "180X", "181X", "181X", "182X", "182X"),
                      pop1 = c("4675,0", "4739,3", "4834,0", "4930,0", "5029,0", "5129,0", "5231,9", "5297,0", "5362,0"),
                      year2 = c(1900L, 1901L, 1902L, 1903L, 1904L, 1905L, 1906L, 1907L, 1908L),
                      pop2 = c("6453,0", "6553,5", "6684,0", "6818,0", "6955,0", "7094,0", "7234,7", "7329,0", "7422,0"), 
                      year3 = c(1930L, 1931L, 1932L, 1933L, 1934L, 1935L, 1936L, 1937L, 1938L),
                      pop3 = c("9981,2", "10583,5", "8671,0", "9118,0", "9625,0", "8097,0", "7984,7", "8729,0", "10462,0")),
                 .Names = c("year1", "pop1", "year2", "pop2", "year3", "pop3"), class = "data.frame", row.names = c(NA, -9L))

如果有很多列,可以使用rbindlist(lapply(split(seq_along(df1),as.numeric(gl(ncol(df1), 2, ncol(df1)))),function(x) df1[x])) - akrun
1
@DavidArenburg 是的,已经移除了 - Jaap

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接