仅在特定条件下折叠数据框中的个案

时间:2016-11-03 11:47:29

标签: r dataframe data-manipulation

我想在Id_no上折叠下面的数据集,但只有在其他变量满足某些条件并计算特殊的折叠变量时才会折叠。

df <- structure(list(Id_no = structure(c(1L, 1L, 1L, 2L, 2L, 3L), .Label = c("n1", 
"n2", "n3"), class = "factor"), Band = structure(c(1L, 2L, 3L, 
1L, 2L, 1L), .Label = c("Band 1", "Band 2", "Band 3"), class = "factor"), 
    median = c(252, 191, 107, 130.5, 61.5, 217), sample_size = c(19L, 
    20L, 1L, 20L, 12L, 1544L)), .Names = c("Id_no", "Band", "median", 
"sample_size"), class = "data.frame", row.names = c(NA, -6L))

> df
  Id_no   Band median sample_size
1    n1 Band 1  252.0          19
2    n1 Band 2  191.0          20
3    n1 Band 3  107.0           1
4    n2 Band 1  130.5          20
5    n2 Band 2   61.5          12
6    n3 Band 1  217.0        1544

崩溃变量是Band 1中位数与2和3之间平均中位数之比。

这将针对Id_no计算,其实际上具有B1和B2或B3中的至少一个的条目。

此外,仅当样本量≥10时才应考虑B2和B3中位数。

我正在寻找的结果表是:

  Id_no b1_vs_rest
1    n1       1.32
2    n2       2.12

第一步可能是删除样本量不符合最小值的情况:

df <- subset(df, sample_size >=10)

3 个答案:

答案 0 :(得分:1)

这是一个使用dplyrif...else构造来改变条件输出的解决方案。根据你的问题(而不是你预期的结果),我假设你想要乐队1的中位数与乐队2和3的中位数的平均比例,如果你有三个。

d2 <- df %>%
  filter(sample_size >= 10) %>%
  group_by(Id_no) %>%
  summarise(b1_vs_rest = if(any(Band == "Band 2") & any(Band == "Band 3")) {
                           median[Band == "Band 1"] / (mean(c(median[Band == "Band 2"], median[Band == "Band 3"])))
                         } else if(any(Band == "Band 2")) {
                           median[Band == "Band 1"] / median[Band == "Band 2"]
                         } else if(any(Band == "Band 3")) {
                           median[Band == "Band 1"] / median[Band == "Band 3"]
                         } else {
                           NA
                         }) %>%
  filter(!is.na(b1_vs_rest))

结果:

> d2
# A tibble: 2 × 2
   Id_no b1_vs_rest
  <fctr>      <dbl>
1     n1   1.319372
2     n2   2.121951

答案 1 :(得分:1)

使用dplyr的一种方法:

library(dplyr)
res <- df %>% group_by(Id_no) %>% 
              filter(sample_size >= 10) %>%
              summarise(b1_vs_rest=median[Band == "Band 1"]/mean(median[Band != "Band 1"])) %>%
              filter(!is.nan(b1_vs_rest))

注意:

  1. 使用dplyr,首先filter仅保留sample_size大于或等于10的行。
  2. 然后group_by Id_nosummarise计算每个Id_no选择分子median Band == "Band 1""Band 1"的比率所有其他乐队的中位数。
  3. 如果"Band 2"mean都不存在,那么NaN将返回NaN,结果也将是filter。因此,我们NaN再次仅保留非print(res) ### A tibble: 2 x 2 ## Id_no b1_vs_rest ## <fctr> <dbl> ##1 n1 1.319372 ##2 n2 2.121951 值。
  4. 使用您的数据的结果符合预期:

    {{1}}

答案 2 :(得分:1)

以下是使用data.table的选项。转换&#39; data.frame&#39;到&#39; data.table&#39; (setDT(df)),重塑长期&#39;广泛的&#39; (dcast),删除NA行(na.omit),将.SDcols指定为&#39; Band&#39;列,将第一列(.SD[[1]])除以其他列(Reduce(`+`, ...))的总和,以获得预期的输出。

library(data.table)#1.9.7+
na.omit(dcast(setDT(df)[sample_size >= 10], Id_no~Band, value.var = "median"))[,
  .(Id_no, b1_vs_rest = .SD[[1]]/Reduce(`+`, .SD[, -1, with = FALSE])) , .SDcols = -1]
#   Id_no b1_vs_rest
#1:    n1   1.319372
#2:    n2   2.121951