将行索引传播到R中的列中

时间:2016-12-02 13:56:59

标签: r dataframe data.table dplyr

我在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循环,但它相当慢,并且需要很长时间才能完成我的数据集,所以任何更快的建议都会很棒。谢谢!

1 个答案:

答案 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。)