在R

时间:2017-09-06 01:29:32

标签: r dataframe dplyr reshape collapse

我对R比较陌生,每次我需要重塑"数据,我绝对感到困惑。我的数据看起来像这样:

HAVE:

  ID ever_smoked alcoholic        medication dosage
1  1          no        no humira/adalimumab   40mg
2  1          no        no        prednisone   15mg
3  1          no        no      azathioprine   30mg
4  1          no        no            rowasa    9mg
5  2         yes        no            lialda   20mg
6  2         yes        no    mercaptopurine     1g
7  2         yes        no            asacol 1600mg

WANT:

 ID  ever_smoked  alcoholic  medication
1  1          no        no   humira/adalimumab, prednisone, azathioprine, rowasa
2  2         yes        no   lialda, mercaptopurine, asacol

  dosage                  most_recent_med     most_recent_dose
1 40mg, 15mg, 30mg, 9mg   rowasa              9mg
2 20mg, 1g, 1600mg        asacol              1600mg

(请注意,它应该是2个观察值和7个变量)。

本质上,我想(1)只折叠一些变量,(2)保留其他变量的第一行,并且(3)根据某些变量的最后一个条目创建2个新变量变量。

重现的代码:

have <- data.frame(ID = c(1, 1, 1, 1, 2, 2, 2),
    ever_smoked = c("no", "no", "no", "no", "yes", "yes", "yes"), 
    alcoholic = c("no", "no", "no", "no", "no", "no", "no"),
    medication = c("humira/adalimumab", "prednisone", "azathioprine", "rowasa", "lialda", "mercaptopurine", "asacol"),
    dosage = c("40mg", "15mg", "30mg", "9mg", "20mg", "1g", "1600mg"), stringsAsFactors = FALSE)

want <- data.frame(ID = c(1, 2),
    ever_smoked = c("no", "yes"), 
    alcoholic = c("no", "no"),
    medication = c("humira/adalimumab, prednisone, azathioprine, rowasa", "lialda, mercaptopurine, asacol"),
    dosage = c("40mg, 15mg, 30mg, 9mg", "20mg, 1g, 1600mg"),
    most_recent_med = c("rowasa", "asacol"),
    most_recent_dose = c("9mg", "1600mg"), stringsAsFactors = FALSE)

感谢。

2 个答案:

答案 0 :(得分:4)

以下是一些不同的方法:

1)sqldf

library(sqldf)
sqldf("select ID, 
              ever_smoked, 
              alcoholic, 
              group_concat(medication) as medication,
              group_concat(dosage) as dosage, 
              medication as last_medication, 
              dosage as last_doage
        from have
        group by ID")

,并提供:

  ID ever_smoked alcoholic                                       medication             dosage last_medication last_doage
1  1          no        no humira/adalimumab,prednisone,azathioprine,rowasa 40mg,15mg,30mg,9mg          rowasa        9mg
2  2         yes        no                     lialda,mercaptopurine,asacol     20mg,1g,1600mg          asacol     1600mg

2)data.table

library(data.table)
have_dt <- data.table(have)
have_dt[, list(medication = toString(medication),
               dosage = toString(dosage),
               last_medication = medication[.N],
               last_dosage = dosage[.N]),
           by = "ID,ever_smoked,alcoholic"]

,并提供:

   ID ever_smoked alcoholic                                          medication                dosage last_medication last_dosage
1:  1          no        no humira/adalimumab, prednisone, azathioprine, rowasa 40mg, 15mg, 30mg, 9mg          rowasa         9mg
2:  2         yes        no                      lialda, mercaptopurine, asacol      20mg, 1g, 1600mg          asacol      1600mg

3)base - by

do.call("rbind", by(have, have$ID, with, data.frame(
     ID = ID[1], 
     ever_smoked = ever_smoked[1], 
     alcoholic = alcoholic[1],
     medication = toString(medication),
     dosage = toString(dosage),
     last_medication = tail(medication, 1),
     last_dosage = tail(dosage, 1))))

,并提供:

  ID ever_smoked alcoholic                                          medication                dosage last_medication last_dosage
1  1          no        no humira/adalimumab, prednisone, azathioprine, rowasa 40mg, 15mg, 30mg, 9mg          rowasa         9mg
2  2         yes        no                      lialda, mercaptopurine, asacol      20mg, 1g, 1600mg          asacol      1600mg

请注意,这可以写成:

do.call("rbind", by(have, have$ID, function(x) with(x, data.frame(
     ID = ID[1], 
     ever_smoked = ever_smoked[1], 
     alcoholic = alcoholic[1],
     medication = toString(medication),
     dosage = toString(dosage),
     last_medication = tail(medication, 1),
     last_dosage = tail(dosage, 1)))))

4)base - aggregate

aggregate(. ~ ID + ever_smoked + alcoholic, have,
  function(x) c(values = toString(x), last = as.character(tail(x, 1))))

,并提供:

  ID ever_smoked alcoholic                                   medication.values medication.last         dosage.values dosage.last
1  1          no        no humira/adalimumab, prednisone, azathioprine, rowasa          rowasa 40mg, 15mg, 30mg, 9mg         9mg
2  2         yes        no                      lialda, mercaptopurine, asacol          asacol      20mg, 1g, 1600mg      1600mg

请注意,这将返回一个2 x 5数据框,其中最后两列是每个2列矩阵,这比拼合形式更方便索引,但如果首选扁平,则:do.call("data.frame", DF)

答案 1 :(得分:3)

这是一个摘要流程,您可以使用summarise_all并传递两个函数来汇总每一列:一列用toString折叠列,一列用last取最后一行:

have %>% 
    group_by(ID, ever_smoked, alcoholic) %>% 
    summarise_all(funs(toString(.), most_recent = last(.)))

# A tibble: 2 x 7
# Groups:   ID, ever_smoked [?]
#     ID ever_smoked alcoholic                                 medication_toString       dosage_toString medication_most_recent dosage_most_recent
#  <dbl>       <chr>     <chr>                                               <chr>                 <chr>                  <chr>              <chr>
#1     1          no        no humira/adalimumab, prednisone, azathioprine, rowasa 40mg, 15mg, 30mg, 9mg                 rowasa                9mg
#2     2         yes        no                      lialda, mercaptopurine, asacol      20mg, 1g, 1600mg                 asacol             1600mg

假设 ever_smoked alcoholic 对于每个ID都是唯一的。