在R中将2列数据(从长格式转换为宽格式)扩展为4列。

3

我有这样的数据

id  year    facname class_code       line_no    value
1     1         A        County           1      county1
1     1         A        County           2      county2
1     1         A        source1          1      9
1     1         A        source1          2      4
1     1         A        source2          1      7
1     1         A        source2          2      2
1     1         A        source3          1      8...

2     1         B        County           1      county1
2     1         B        County           2      county1
2     1         B        source1          1      21
2     1         B        source1          2      9
2     1         B        source2          1      4
2     1         B        source2          2      7 ....

我正在尝试将其转换为类似于以下内容的东西: (请注意,最后三列将相应地具有“spread”值)
id year facname   line_no        County      source1        source2      source3
1   1    A       1               county1      9                7           8      
1   2    A       2               county2      4                2           NA
1   3    A       3               county3             
1   4    A       4               county4
2   1    B       1               county1
2   2    B       2               county2
2   3    B       3               county3
2   4    B       4               county4 

这将展示不同付款方(source1,source2,source3)和县名(county1,county2)所属的县的数量。 我知道这是一些spread(可能还有gather)的组合,但我无法理解它。 非常感谢您的任何帮助! (PS:我知道这可能是一个重复的问题,但我真的很新于整理数据)
编辑:县(county1,2等)实际上是数字(在原始数据集中),但其性质是分类的,因此我将其称为县1,其他值(来源)实际上是参与该县事件的人数(source1,source2等)。每个设施有40个line_no。

基本上在这种情况下,县(county1,county2等)是数字县代码(分类)。为了简单起见,我使用county1、county2代替它们各自的县代码(“01”、“20”)。而其他的是数字(source1有2人,source2有3人等)。由于值列(原始数据集)的性质是数值型的,我无法形成逻辑来使用spread。我最初复制行号时犯了一个错误,现在已经更正了。对于造成的混乱,我表示歉意。 - Anurag Kaushik
没问题。但是你在一些行中提到了 county1,而在其他行中提到了一个 number。为了保持一致性,我们能不能使用 county1county2county3 等等呢?你的数据是这样的吗? - MKR
1
@MKR 是的,它们都不是县。每个 facname(设施名称)有40个 line_numbers,其中只有一些付款人(来自 source1、source2 和 source3)。我认为显示所有40个可能不太方便,所以我做了这个修改。抱歉,我应该在 A 和 B 设施之间添加一个“...”来表示它们之间有很多行代码和相应的来源。我会更新帖子的! - Anurag Kaushik
@AnuragKaushik 是的。我想我最终理解了逻辑。我希望其中任何一个答案都能解决您的问题。您可以在真实的数据框上尝试这些。 - MKR
谢谢你们两个!@akrun,抱歉那里有大约40个县。我已根据您的评论编辑了我的帖子。 - Anurag Kaushik
显示剩余2条评论
2个回答

2

一种选择是使用双重的 tidyr::spread,如下所示:

更新: 基于 @CJYetman 的评论

library(dplyr)
library(tidyr)

# Just spread can transform and work on present sample data used by OP
df %>% spread(class_code, value)

#The complicated version below based was initially used to handle different
#line numbers for rows with "County" and rows without "County"
filter(df, class_code == "County") %>% spread(class_code, value) %>% 
left_join(filter(df, class_code != "County") %>% spread(class_code, value),
  by=c("id", "line_no", "facname")) 

#   id facname line_no  County source1 source2 source3
# 1  1       A       1 county1       9       7       8
# 2  1       A       2 county2       4       2    <NA>
# 3  2       B       1 county1      21       4    <NA>
# 4  2       B       2 county1       9       7    <NA>

数据:

df <- read.table(text = 
"id  facname class_code       line_no    value
1   A        County           1      county1
1   A        County           2      county2
1   A        source1          1      9
1   A        source1          2      4
1   A        source2          1      7
1   A        source2          2      2
1   A        source3          1      8
2   B        County           1      county1
2   B        County           2      county1
2   B        source1          1      21
2   B        source1          2      9
2   B        source2          1      4
2   B        source2          2      7",
header = TRUE, stringsAsFactors = FALSE)

我尝试了一下,发现出现了和之前使用spread时一样的错误(当然,它远没有你发布的那个复杂)。我很喜欢你所使用的逻辑,因为我正试图提高我的整洁和dplyr技能。这个错误是“行的重复标识符”,我不太明白它的意思。非常感谢你的帮助,我会在完成项目后继续尝试这个解决方案。 :) - Anurag Kaushik
1
@CJYetman 您说得完全正确。实际上,最初数据和预期输出存在一些混淆。正如您所注意到的那样,OP 仍然在他的实际数据框中遇到了一些问题。我会编辑答案,并将您的评论放入其中,因为我可以看到当前的解决方案正在使其他人感到困惑。 - MKR
1
@MKR 非常感谢!这个简单的代码实际上起作用了。给我提供数据的人错过了一个关键组成部分,即“观察年份”。我承认这完全是我的错,因为我没有早些时候跟进并检查数据的准确性!CJ Yetman 给出的基本解决方案就是得出答案的方法!由于周末我无法访问数据,所以我无法更新!谢谢大家! - Anurag Kaushik
1
我已经相应地更新了帖子,所以如果有人来到这个页面不会感到困惑。 - Anurag Kaushik

2
我们可以使用来自data.table的dcast。
library(data.table)
dcast(setDT(df1), id + facname + rowid(class_code) ~ class_code, value.var = 'value')
#     id facname class_code  County source1 source2 source3
#1:  1       A          1 county1       9       7       8
#2:  1       A          2 county2       4       2      NA
#3:  2       B          3 county1      21       4      NA
#4:  2       B          4 county1       9       7      NA

如果我们需要如预期输出中的8行:
dcast(setDT(df1), id + facname + rowid(class_code) ~ class_code, 
    value.var = 'value', drop = FALSE)[ ,.SD[!all(is.na(County))], .(id, facname)]
#   id facname class_code  County source1 source2 source3
#1:  1       A          1 county1       9       7       8
#2:  1       A          2 county2       4       2      NA
#3:  1       A          3      NA      NA      NA      NA
#4:  1       A          4      NA      NA      NA      NA
#5:  2       B          1      NA      NA      NA      NA
#6:  2       B          2      NA      NA      NA      NA
#7:  2       B          3 county1      21       4      NA
#8:  2       B          4 county1       9       7      NA

第一个几乎接近我想要的!我希望将line_no变成一列,而不是class_code。我会尝试调整代码,但如果您能编辑您的答案,我将非常感激:D!非常感谢! - Anurag Kaushik
@AnuragKaushik 这很容易做到。setDT(df1)[, line_no: rowid(class_code); dcast(df1, id + facname + line_no ~ class_code, ... - akrun

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