我在R中有一个数据框,格式如下:
> old.dat
id type minDate maxDat eventNum
1 001 A may june 1
2 002 B apr oct 1
3 002 C may nov 2
4 002 B july dec 3
我想根据eventNum
将行转换为列。最高eventNum
为3,因此如果某些ID只有1 eventNum
,我希望它们填充NA
。
目标:
id type1 minDate1 maxDat1 eventNum1 type2 minDate2 maxDat2 eventNum2 type3 minDate3 maxDat3 eventNum3
1 001 A may june 1 <NA> <NA> <NA> NA <NA> <NA> <NA> NA
2 002 B apr oct 1 C may nov 2 B july dec 3
这是一个引入起点的代码块。
old.dat <- data.frame(id = c("001","002","002","002"),
type = c("A","B","C","B"),
minDate = c("may","apr","may","july"),
maxDat = c("june", "oct", "nov", "dec"),
eventNum = c(1,1,2,3))
我写了一个for循环,但它相当慢,并且需要很长时间才能完成我的数据集,所以任何更快的建议都会很棒。谢谢!
答案 0 :(得分:2)
为什么呢?我不知道我是否可以想象这种格式有用的情况,但这是一种使用tidyr
的方法。
首先,我保存了一个新列名列表,以便更容易理解:
newCols <- c("type", "minDate", "MaxDat")
(我将在下面添加数字)。
然后,我unite
为每个事件提供您想要的值,spread
结果为每个eventNum
获取一个新列,然后separate
结果返回到单独的列中(并将事件的编号附加到其中)
old.dat %>%
unite(toSpread, type, minDate, maxDat, sep = "::") %>%
spread(eventNum, toSpread) %>%
separate(`1`, paste0(newCols, "_1"), sep = "::") %>%
separate(`2`, paste0(newCols, "_2"), sep = "::") %>%
separate(`3`, paste0(newCols, "_3"), sep = "::")
返回:
id type_1 minDate_1 MaxDat_1 type_2 minDate_2 MaxDat_2 type_3 minDate_3 MaxDat_3
1 001 A may june <NA> <NA> <NA> <NA> <NA> <NA>
2 002 B apr oct C may nov B july dec
这是一种替代方法,首先将数据转换为长格式(使用gather
),然后生成新的列名并进行传播。新列的复杂mutate
行分配因子级别仅用于对列进行排序,并使用parse_number
中的readr
来提取事件编号。如果输入列按字母顺序排序,则可以跳过该步骤。此方法对其他事件编号很稳健,因为它会自动为eventNum
中的每个唯一值添加事件。
old.dat %>%
gather(Metric, Value, type, minDate, maxDat) %>%
unite(newColHead, Metric, eventNum) %>%
mutate(newColHead = factor(newColHead
, levels =
unique(newColHead) %>%
{.[order(parse_number(.))]}
)) %>%
spread(newColHead, Value)
对于此用例,输出与上述相同。
(并且,如果你想要证明为什么这可能更好;请注意我的编辑 - 我最初错误标记了事件编号2/3。)