【问题标题】:Calculate results between columns according different parameters in sql, r or python根据sql、r或python中的不同参数计算列之间的结果
【发布时间】:2018-07-26 08:12:14
【问题描述】:

大家好,我有这个问题,我正在计算日期之间的天数,前提如下:

  • 状态A是基准日期,所有计算都必须以这个日期为参考(按ID分组)
  • 对于状态 B、C、D,我必须选择较早的日期
  • 我必须计算天数并显示在不同的列中

例如

用 R 生成表格

ColID = c(1, 1, 1, 1, 1, 2, 2, 2)        
ColStatus = c("A", "B", "B", "C", "D", "A", "C", "C")
ColDate = c("01/01/2018","02/03/2018", "05/04/2018", "04/05/2018", "04/05/2018", "02/01/2018", "04/03/2018", "05/04/2018")
data.frame(ColID, ColStatus, ColDate)

我如何进行计算

For ColID = 1

Status A = 01/01/2018
Status B (I Have to select the older one) = 02/03/2018
Status C = 04/05/2018
Status D = 04/05/2018

ResultColB = 02/03/2018 - 01/01/2018 = 60
ResultColC = 04/05/2018 - 01/01/2018 = 123
ResultColD = 04/05/2018 - 01/01/2018 = 123

结果表(以天为单位)

用 R 生成表格

ColID = c(1,2)
ResultColStatusB = c(60,0)
ResultColStatusC = c(123,61)
data.frame(ColID, ResultColStatusB, ResultColStatusC, ResultColStatusB)

这个问题可以用 R、Python 或 SQL 解决,有什么建议我来解决这个问题?

【问题讨论】:

    标签: python mysql sql r


    【解决方案1】:

    这是 R 中的 tidyverse 解决方案:

    library(lubridate)
    library(tidyverse)
    
    df %>%
      group_by(ColID, ColStatus) %>% 
      summarise(min_date = min(parse_date_time(ColDate, "%d/%m/%Y"))) %>%
      group_by(ColID) %>%
      summarise(a_b = as.period(interval(min_date[ColStatus=="A"], 
                                         min_date[ColStatus=="B"])) %/% days(1) - 1,
                a_c = as.period(interval(min_date[ColStatus=="A"], 
                                         min_date[ColStatus=="C"])) %/% days(1) - 1,
                a_d = as.period(interval(min_date[ColStatus=="A"], 
                                         min_date[ColStatus=="D"])) %/% days(1) - 1) %>%
    mutate_all(funs(if_else(is.na(.), 0, .)))
    

    输出:

      ColID   a_b   a_c   a_d
      <dbl> <dbl> <dbl> <dbl>
    1    1.   60.  123.  123.
    2    2.    0.   61.    0.
    

    解释:

    1. ColDate转换为日期类型,获取每个ColStatus的最早日期
    2. 计算A 和彼此ColStatus 值之间的时间间隔(以天为单位)。
    3. NA 值转换为0

    R 中使用data.table 的另一种方法:

    setDT(df)
    #convert string Dates to integer
    df[, ColDate := as.numeric(as.Date(ColDate, format="%d/%m/%Y"))]
    cols <- c("B","C","D")
    #pivot table without A into a wide table
    dcast(df[ColStatus!="A"], ColID ~ ColStatus, min, fill=NA_integer_, value.var="ColDate")[ 
        #join with table containing only A and do the differencing
        df[ColStatus=="A"], on=.(ColID),
        (cols) := lapply(.SD, function(x) x - i.ColDate), .SDcols=cols]
    

    或者使用baseR:

    df$ColDate <- as.integer(as.Date(df$ColDate, format="%d/%m/%Y"))
    cols <- c("B","C","D")
    by(df, df$ColID, function(x) {
        aDate <- x$ColDate[x$ColStatus=="A"]
        vapply(cols, 
            function(id) if(any(x$ColStatus==id)) min(x$ColDate[x$ColStatus==id]) - aDate 
                else NA_integer_, 
            integer(1))
    })
    

    数据:

    ColID = c(1, 1, 1, 1, 1, 2, 2, 2)        
    ColStatus = c("A", "B", "B", "C", "D", "A", "C", "C")
    ColDate = c("01/01/2018","02/03/2018", "05/04/2018", "04/05/2018", "04/05/2018", "02/01/2018", "04/03/2018", "05/04/2018")
    df <- data.frame(ColID, ColStatus, ColDate)
    

    【讨论】:

    • 谢谢@chinsoon12!
    • 谢谢!我在执行第一个解决方案 (tidyverse) 时遇到了一个问题。 "Period#ANY", "ANY#Period" 也只是有效的估计:转换为准确的间隔 summarise_impl(.data, dots) 中的错误:评估错误:分配类 logical 对类 Period 的对象中的插槽 .Data 无效; is(value, "numeric") 不是 TRUE。
    【解决方案2】:

    Python:

    import pandas as pd 
    Dic = {'ColID': [1, 1, 1, 1, 1, 2, 2, 2],
           'ColStatus': ["A", "B", "B", "C", "D", "A", "C", "C"], 
           'ColDate': ["01/01/2018", "02/03/2018", "05/04/2018", "04/05/2018",
            "04/05/2018", "02/01/2018", "04/03/2018", "05/04/2018"]} 
    df = pd.DataFrame(Dic) 
    df.ColDate = pd.to_datetime(df.ColDate, format='%d/%m/%Y') 
    conditions = [df.ColID==n for n in df.ColID.unique()] 
    choices = [df[(df.ColID==n) & (df.ColStatus=='A')]['ColDate'].min() for n in df.ColID.unique()] 
    df['Amin'] = pd.np.select(conditions, choices) 
    df['days'] = df.ColDate - df.Amin 
    df = df[df['days'].dt.days>0]
    

    【讨论】:

    • 操作说明:02/03/2018 - 01/01/2018 = 60...看起来像 D/M/Y
    猜你喜欢
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 2022-07-29
    • 1970-01-01
    • 1970-01-01
    • 2014-08-03
    • 2021-01-14
    相关资源
    最近更新 更多