【问题标题】:Count distinct values that are not the same as the current row's values计算与当前行的值不同的不同值
【发布时间】:2018-04-12 05:52:22
【问题描述】:

假设我有一个数据框:

df <- data.frame(SID=sample(1:4,15,replace=T), Var1=c(rep("A",5),rep("B",5),rep("C",5)), Var2=sample(2:4,15,replace=T))

结果是这样的:

    SID Var1 Var2
1     4    A    2
2     3    A    2
3     4    A    3
4     3    A    3
5     1    A    4
6     1    B    2
7     3    B    2
8     4    B    4
9     4    B    4
10    3    B    2
11    2    C    2
12    2    C    2
13    4    C    4
14    2    C    4
15    3    C    3

我希望完成的是找到排除给定行的 Var1 的唯一 SID 的计数(请参阅下面的更新,这应该说 唯一(SID,Var1)组合的计数)从这个计数中,计数在 Var2 上分组。所以对于上面的例子,我想输出:

    SID Var1 Var2 Count.Excluding.Var1
1     4    A    2                    3
2     3    A    2                    3
3     4    A    3                    1
4     3    A    3                    1
5     1    A    4                    3
6     1    B    2                    3
7     3    B    2                    3
8     4    B    4                    3
9     4    B    4                    3
10    3    B    2                    3
11    2    C    2                    4
12    2    C    2                    4
13    4    C    4                    2
14    2    C    4                    2
15    3    C    3                    2

对于第一次观察,我们的计数为 3,因为对于给定的 Var2 值(在本例中为 2)有 3 个唯一组合(SID,Var1),其中 Var1 != A(第一次观察的 Var1 值) -- 具体来说,计数包括观察 6、7 和 11,但不包括 12,因为我们已经考虑了 (SID, Var1)=(2,C) 而不是第 2 行,因为我们不希望 Var1 是“A”。所有这些行都具有相同的 Var2 值。

我更喜欢使用 dplyr 函数和 %>% 运算符。 &

更新

对于上面的混淆和我的错误解释,我深表歉意。我已经更正了我打算在括号中要求的内容,但我也保留了我原来的措辞,因为大多数答案似乎都是这样解释的。

对于示例,我很抱歉没有设置种子。关于第 11 行和第 12 行的 Count.Excluding.Var1 似乎有些混淆。使用唯一的 (SID, Var1) 组合,第 11 行和第 12 行应该是有意义的,因为这些计数为第 1、2、6 和 7 行异或 8。

【问题讨论】:

  • 上述逻辑中Var2有什么用?
  • 这是我为二进制朴素贝叶斯问题制作的一个通用示例,其中 Var2 是由 Var1 表示的类的特征,而 SID 类似于观察结果。所以我实际上想要做的是找到所有包含 Var2 值但不属于 Var1 类的唯一观察值。
  • 正如@MKR 提到的,逻辑不清楚。请检查预期的输出是否正确
  • 第 11 行和第 12 行是否正确?我认为Count.Excluding.Var1 应该是 3
  • 为什么第三行的 count 是 1?

标签: r dplyr


【解决方案1】:

一个简单的mapply 就可以解决问题。但由于 OP 要求基于 %>% 的解决方案,一个选项可能是:

df %>% mutate(Count.Excluding.Var1 = 
  mapply(function(x,y)nrow(unique(df[df$Var1 != x & df$Var2 == y,1:2])),.$Var1,.$Var2))
#     SID Var1 Var2 Count.Excluding.Var1
# 1    4    A    2                    3
# 2    2    A    3                    3
# 3    4    A    4                    3
# 4    4    A    4                    3
# 5    3    A    4                    3
# 6    4    B    3                    1
# 7    3    B    3                    1
# 8    3    B    3                    1
# 9    4    B    2                    3
# 10   2    B    3                    1
# 11   2    C    2                    2
# 12   4    C    4                    2
# 13   1    C    4                    2
# 14   1    C    2                    2
# 15   3    C    4                    2

数据:

以上结果基于 OP 提供的原始数据。

df <- data.frame(SID=sample(1:4,15,replace=T), Var1=c(rep("A",5),rep("B",5),rep("C",5)), Var2=sample(2:4,15,replace=T))

【讨论】:

    【解决方案2】:

    想不出dplyr 的解决方案,但这是apply 的解决方案

    df$Count <- apply(df, 1, function(x) length(unique(df$SID[(df$Var1 != x['Var1']) & (df$Var2 == x['Var2'])])))
    #     SID Var1 Var2 Count
    # 1    4    A    2     3
    # 2    3    A    2     3
    # 3    4    A    3     1
    # 4    3    A    3     1
    # 5    1    A    4     2
    # 6    1    B    2     3
    # 7    3    B    2     3
    # 8    4    B    4     3
    # 9    4    B    4     3
    # 10   3    B    2     3
    # 11   2    C    2     3
    # 12   2    C    2     3
    # 13   4    C    4     2
    # 14   2    C    4     2
    # 15   3    C    3     2
    

    【讨论】:

      【解决方案3】:

      根据要求,这是一个dplyr 解决方案。供将来参考,请使用set.seed,以便我们可以使用sample 重现您想要的输出,否则我必须手动输入数据...

      我认为这是你的逻辑?您希望每个Var2 都使用n_distinct(SID),但是对于每一行,您希望排除与当前行具有相同Var1 的行。所以这里的一个关键观察是第 3 行,其中一个简单的分组汇总将产生 2 的计数。在带有 Var2 = 3 的行中,第 3 行有 SID = 4,第 4 行有 SID = 3,第 15 行有 SID = 3,但我们不计算第 3 行或第 4 行,因此最终计数是唯一的 SID

      在这里,我们首先获得每个 Var2 的唯一 SID 计数,然后是每个 Var1, Var2 组合的唯一 SID 计数。对于每个组合,第一个计数与 additional 唯一 SID 的数量相比太大了,因此我们将其减去并添加一个。有一种极端情况,对于Var1,只有一个对应的Var2。这应该返回0,因为您排除了SID 的所有可能值。我添加了两行来说明这一点。

      library(tidyverse)
      df <- read_table2(
        "SID Var1 Var2
      4    A    2
      3    A    2
      4    A    3
      3    A    3
      1    A    4
      1    B    2
      3    B    2
      4    B    4
      4    B    4
      3    B    2
      2    C    2
      2    C    2
      4    C    4
      2    C    4
      3    C    3
      1    D    5
      2    D    5"
      )
      
      df %>%
        group_by(Var2) %>%
        mutate(SID_per_Var2 = n_distinct(SID)) %>%
        group_by(Var1, Var2) %>%
        mutate(SID_per_Var1Var2 = n_distinct(SID)) %>%
        ungroup() %>% 
        add_count(Var1) %>%
        add_count(Var1, Var2) %>%
        mutate(
          Count.Excluding.Var1 = if_else(
            n > nn,
            SID_per_Var2 - SID_per_Var1Var2 + 1,
            0
          )
        ) %>%
        select(SID, Var1, Var2, Count.Excluding.Var1)
      #> # A tibble: 17 x 4
      #>      SID Var1   Var2 Count.Excluding.Var1
      #>    <int> <chr> <int>                <dbl>
      #>  1     4 A         2                   3.
      #>  2     3 A         2                   3.
      #>  3     4 A         3                   1.
      #>  4     3 A         3                   1.
      #>  5     1 A         4                   3.
      #>  6     1 B         2                   3.
      #>  7     3 B         2                   3.
      #>  8     4 B         4                   3.
      #>  9     4 B         4                   3.
      #> 10     3 B         2                   3.
      #> 11     2 C         2                   4.
      #> 12     2 C         2                   4.
      #> 13     4 C         4                   2.
      #> 14     2 C         4                   2.
      #> 15     3 C         3                   2.
      #> 16     1 D         5                   0.
      #> 17     2 D         5                   0.
      

      reprex package (v0.2.0) 于 2018 年 4 月 12 日创建。

      【讨论】:

        【解决方案4】:

        这是使用 purrr 的解决方案 - 如果需要,您可以将其包装在 mutate 语句中,但我不知道它在这种特殊情况下会增加多少。

        library(purrr)
        df$Count.Excluding.Var1 = map_int(1:nrow(df), function(n) {
          df %>% filter(Var2 == Var2[n], Var1 != Var1[n]) %>% distinct() %>% nrow()
        })
        

        (根据 Calum You 的 cmets 输入更新。谢谢!)

        【讨论】:

          【解决方案5】:

          100% tidyverse 解决方案:

          library(tidyverse) # dplyr + purrr
          df  %>%
            group_by(Var2) %>%
            mutate(count = map_int(Var1,~n_distinct(SID[.x!=Var1],Var1[.x!=Var1])))
          
          # # A tibble: 15 x 4
          # # Groups:   Var2 [3]
          #      SID  Var1  Var2 count
          #    <int> <chr> <int> <int>
          #  1     4     A     2     3
          #  2     3     A     2     3
          #  3     4     A     3     1
          #  4     3     A     3     1
          #  5     1     A     4     3
          #  6     1     B     2     3
          #  7     3     B     2     3
          #  8     4     B     4     3
          #  9     4     B     4     3
          # 10     3     B     2     3
          # 11     2     C     2     4
          # 12     2     C     2     4
          # 13     4     C     4     2
          # 14     2     C     4     2
          # 15     3     C     3     2
          

          【讨论】:

            猜你喜欢
            • 2021-12-25
            • 2017-09-14
            • 1970-01-01
            • 2022-11-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多