【问题标题】:Dcast multiple observation in a 1 cell in R在R中的1个单元格中进行多次观察
【发布时间】:2017-04-26 08:09:27
【问题描述】:

我有一个 R 数据框

Customer    Month   BaseVolume  IncrementalVolume   TradeSpend
10          Jan         11            1             110
10          Feb         12            2             120
20          Jan         21            7             210
20          Feb         22            8             220

我想这样转换它,

Customer    Jan                    Feb  
10          BaseVolume 11         BaseVolume 12
            IncrementalVolume 1   IncrementalVolume 2 
            TradeSpend 110        TradeSpend 120

20         BaseVolume 21          BaseVolume 22
           IncrementalVolume 7    IncrementalVolume 8 
           TradeSpend 210         TradeSpend 220     

我尝试了 dcast (reshape),但我无法得到这个结果。请帮帮我

【问题讨论】:

    标签: r dataframe dcast


    【解决方案1】:

    虽然已经有an answer,但我觉得它在某些方面可以改进以更接近预期的输出:

    • OP 已指定要按顺序出现的月份Jan, Feb
    • 输出难以阅读
    • 应该在dcast()之前对列进行修改

    我们首先将输入数据从宽格式改成长格式,但要确保Month 以正确的顺序出现:

    molten <- melt(dt1, id.vars = c("Customer", "Month"))
    # turn Month into factor with levels in the given order
    molten[, Month := forcats::fct_inorder(Month)]
    

    现在,在调用dcast()之前以长格式创建了一个新的text 列:

    molten[, text := paste(variable, value)]
    dcast(molten, Customer + variable ~ Month, value.var = "text")[, variable := NULL][]
    #   Customer                 Jan                 Feb
    #1:       10       BaseVolume 11       BaseVolume 12
    #2:       10 IncrementalVolume 1 IncrementalVolume 2
    #3:       10      TradeSpend 110      TradeSpend 120
    #4:       20       BaseVolume 21       BaseVolume 22
    #5:       20 IncrementalVolume 7 IncrementalVolume 8
    #6:       20      TradeSpend 210      TradeSpend 220
    

    结果类似于this answer,但月份按预期顺序排列。


    注意不幸的是,折叠每个 Customer 的行的方法不起作用,因为打印时不遵守换行符:

    dcast(molten, Customer ~ Month, value.var = "text", paste0, collapse = "\n")
    #   Customer                                                Jan                                                Feb
    #1:       10 BaseVolume 11\nIncrementalVolume 1\nTradeSpend 110 BaseVolume 12\nIncrementalVolume 2\nTradeSpend 120
    #2:       20 BaseVolume 21\nIncrementalVolume 7\nTradeSpend 210 BaseVolume 22\nIncrementalVolume 8\nTradeSpend 220
    

    text 列可以通过向右填充空白来左对齐(最小长度由最长字符串的字符长度决定):

    molten[, text := paste(variable, value)]
    molten[, text := stringr::str_pad(text, max(nchar(text)), "right")]
    dcast(molten, Customer + variable ~ Month, value.var = "text")[, variable := NULL][]
    #   Customer                 Jan                 Feb
    #1:       10 BaseVolume 11       BaseVolume 12      
    #2:       10 IncrementalVolume 1 IncrementalVolume 2
    #3:       10 TradeSpend 110      TradeSpend 120     
    #4:       20 BaseVolume 21       BaseVolume 22      
    #5:       20 IncrementalVolume 7 IncrementalVolume 8
    #6:       20 TradeSpend 210      TradeSpend 220     
    

    或者,text 列可以自身对齐:

    fmt <- stringr::str_interp("%-${n}s %3i", list(n = molten[, max(nchar(levels(variable)))]))
    molten[, text := sprintf(fmt, variable, value)]
    dcast(molten, Customer + variable ~ Month, value.var = "text")[, variable := NULL][]
    #   Customer                   Jan                   Feb
    #1:       10 BaseVolume         11 BaseVolume         12
    #2:       10 IncrementalVolume   1 IncrementalVolume   2
    #3:       10 TradeSpend        110 TradeSpend        120
    #4:       20 BaseVolume         21 BaseVolume         22
    #5:       20 IncrementalVolume   7 IncrementalVolume   8
    #6:       20 TradeSpend        210 TradeSpend        220
    

    这里,sprintf() 中使用的格式也是使用字符串插值动态创建的:

    fmt
    #[1] "%-17s %3i"
    

    注意variable 的最长 的字符长度在此处使用,因为melt() 已默认将variable 转换为因子。


    答案可能要简单得多,因为最新版本的 data.table 允许同时重塑多个列:

    molten <- melt(dt1, id.vars = c("Customer", "Month"))
    molten[, Month := forcats::fct_inorder(Month)]
    dcast(molten, Customer + variable ~ Month, value.var = c("variable", "value"))
    #   Customer          variable    variable.1_Jan    variable.1_Feb value_Jan value_Feb
    #1:       10        BaseVolume        BaseVolume        BaseVolume        11        12
    #2:       10 IncrementalVolume IncrementalVolume IncrementalVolume         1         2
    #3:       10        TradeSpend        TradeSpend        TradeSpend       110       120
    #4:       20        BaseVolume        BaseVolume        BaseVolume        21        22
    #5:       20 IncrementalVolume IncrementalVolume IncrementalVolume         7         8
    #6:       20        TradeSpend        TradeSpend        TradeSpend       210       220
    

    但不幸的是,它缺少以交替顺序轻松重新排序列的选项,即所有列属于Jan,然后是Feb 等。

    【讨论】:

    【解决方案2】:

    您可以尝试以下方法(在您的情况下,假设您的数据是 df1,您需要在我提到的任何操作之前执行 setDT(df1)):

    library(data.table)
    dt1 <- structure(list(Customer = c(10L, 10L, 20L, 20L), Month = c("Jan", 
    "Feb", "Jan", "Feb"), BaseVolume = c(11L, 12L, 21L, 22L), IncrementalVolume = c(1L, 
    2L, 7L, 8L), TradeSpend = c(110L, 120L, 210L, 220L)), .Names = c("Customer", 
    "Month", "BaseVolume", "IncrementalVolume", "TradeSpend"), row.names = c(NA, 
    -4L), class = c("data.table", "data.frame"))
    
    res <- dcast(melt(dt1, id.vars = c("Customer", "Month")), Customer + variable~ Month)
    
    > res
       Customer          variable Feb Jan
    1:       10        BaseVolume  12  11
    2:       10 IncrementalVolume   2   1
    3:       10        TradeSpend 120 110
    4:       20        BaseVolume  22  21
    5:       20 IncrementalVolume   8   7
    6:       20        TradeSpend 220 210
    

    如果您希望它们在一起,您可以执行以下操作:

    update_cols <- which(!names(res) %in% c("Customer", "variable"))
    res[, (update_cols):= lapply(.SD, function(x) paste(variable, x)), .SDcols = update_cols][, variable:= NULL]
    

    这给出了:

    > res
         Customer            Feb                 Jan
    1:       10       BaseVolume 12       BaseVolume 11
    2:       10 IncrementalVolume 2 IncrementalVolume 1
    3:       10      TradeSpend 120      TradeSpend 110
    4:       20       BaseVolume 22       BaseVolume 21
    5:       20 IncrementalVolume 8 IncrementalVolume 7
    6:       20      TradeSpend 220      TradeSpend 210
    

    【讨论】:

    • 完美。谢谢@User2321
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-27
    • 1970-01-01
    • 1970-01-01
    • 2018-06-11
    • 1970-01-01
    相关资源
    最近更新 更多