【问题标题】:Merging Similar Observations in R在 R 中合并相似的观察
【发布时间】:2014-10-11 23:31:34
【问题描述】:

我正在尝试使用 R 进行一些数据管理。

我有一个数据框,它包含多个变量(+200 列)和许多观察值(+10,000 行)。有很多缺失的数据,以及重复或未完成的观察。 一个观察值应该等于一个人(1 行 = 1 个唯一的人)

这是数据集示例(感谢@aosmith):

dat = data.frame(email = c(rep(c("user1@hotmail.com", "user2@gmail.com"), each = 2), NA),
              name = c(NA, "Alfred C.", NA, "Bob V.", "Cathy L."),
              var1 = c(2, 2, NA, NA, 1),
              var2 = c(1, NA, 3, NA, 1),
              var3 = c(NA, NA, 1, 0, 2),
              var4 = c(0, NA, NA, NA, NA))

我想合并我的观察结果,最后,一行等于一个人。为了识别一个人,我使用电子邮件。当没有电子邮件时,我想保留所有观察结果(因此,如果电子邮件丢失,我不希望 R 删除观察结果。没有电子邮件的每个观察结果都被视为唯一观察结果)。

当我们可以发现相同的电子邮件地址时,我们需要 R 更新每个变量的字段,当缺少数据时使用我们在后续观察中获得的数据(使用相同的电子邮件地址)我们发现。如果已经存在一个或多个变量的数据,我们希望 R 创建一个新变量来存储不同的值。

这是一个更容易理解的例子。

我们需要这样改造:

          email        name    var1 var2 var3 var4 ... var200
user1@hotmail.com      <NA>     2    1   NA    0   ...   .
user1@hotmail.com    Alfred C.  2   NA   NA   NA   ...   .
  user2@gmail.com      <NA>    NA    3    1   NA   ...   .
  user2@gmail.com     Bob V.   NA   NA    0   NA   ...   .
             <NA>    Cathy L.   1    1    2   NA   ...   .

类似这样的东西(将行与相同的电子邮件组合并将同一个人的所有信息保留在一行中,但当我们无法识别该人与电子邮件地址相同时,也通过保留信息。所以如果email 是 NA,我们必须让它像一个独特的人一样):

           email           name      var1    var2    var3a   var3b   var4   ...  var200

  user1@hotmail.com      Alfred C.     2       1      NA       NA     0      .      . 
    user2@gmail.com       Bob V.      NA       3      1        0      NA     .      . 
               <NA>      Cathy L.      1       1      2        .      NA     .      . 
    userX@email.com         .          .      etc    etc      etc    etc    etc    etc 

有没有简单的方法来做到这一点?我在 dplyr 和 tidyr 上苦苦挣扎了两天...... 最后,一行应该包含我们能够使用 email 变量识别的一个人的信息。我们还需要保留所有其他我们无法识别为属于一个人的观察结果。

感谢您的帮助和时间!

【问题讨论】:

  • 你的意思是你要么有电子邮件,要么有推特,还是两者都有?缺少的电子邮件值是否与 NA 一起显示?
  • twitter 只是另一个变量,我认为它令人困惑,所以我将从示例中删除它。我们想合并来自同一个人使用他们的电子邮件地址的观察结果。
  • 我更新了我的答案,这可能有帮助,也可能没有帮助。如果您放入可重现的示例数据集(您的示例数据集没有任何缺失的电子邮件值),将会有所帮助。
  • @aosmith 我更新了我的问题并添加了你建议的可复制数据集

标签: r data-manipulation


【解决方案1】:

我想出了一个选项,以防您不知道主题中的每个变量将具有多少值。您会看到大部分步骤都是为此目的(为单独的列创建单独的名称)。

该过程是使用gather将数据集转换为长格式,删除每个主题和变量组合的缺失值和重复值,当每个变量有多个值时(添加b,c等)创建变量名称. 到变量名称的结尾),然后将数据集放回宽格式并使用spread

dat = data.frame(email = rep(c("user1@hotmail.com", "user2@gmail.com"), each = 2),
                  twitter = c(NA, "user1", NA, "user2"),
                  var1 = c(2, 2, NA, NA),
                  var2 = c(1, NA, 3, NA),
                  var3 = c(NA, NA, 1, 0),
                  var4 = c(0, NA, NA, NA))
library(dplyr)
library(tidyr)

dat %>%
    gather(allvar, value, twitter:var4) %>%
    group_by(email, allvar) %>%
    filter(!is.na(value) & !duplicated(value)) %>%
    mutate(allvar2 = paste0(allvar, c("", letters[2:26])[1:n()])) %>% 
    ungroup() %>%
    select(-allvar) %>%
    spread(allvar2, value, convert = TRUE)

Source: local data frame [2 x 7]

              email twitter var1 var2 var3 var3b var4
1 user1@hotmail.com   user1    2    1   NA    NA    0
2   user2@gmail.com   user2   NA    3    1     0   NA

编辑获取缺少某些电子邮件地址时的新示例

我不完全清楚您是否总是拥有 Twitter 或电子邮件信息或两者兼有 - 如果是这样,我认为这可能会通过在 @jazurro 的答案中填写 na.locf 并使用组合来简化电子邮件和 twitter 作为分组变量。

要保留没有电子邮件的行,您可以将它们过滤掉,做所有您需要的事情,然后 rbind_list 将它们重新输入。在这种情况下,命名重复的变量,例如 var3var3b 将适用您(可以将它们命名为 var3avar3b,但不适用于此 rbinding 方法)。

dat = data.frame(email = c(rep(c("user1@hotmail.com", "user2@gmail.com"), each = 2), NA),
                  twitter = c(NA, "user1", NA, "user2", "user3"),
                  var1 = c(2, 2, NA, NA, 1),
                  var2 = c(1, NA, 3, NA, 1),
                  var3 = c(NA, NA, 1, 0, 2),
                  var4 = c(0, NA, NA, NA, NA))

dat %>%
    filter(!is.na(email)) %>% # filter out rows with missing email
    gather(allvar, value, twitter:var4, na.rm=TRUE) %>%
    group_by(email, allvar) %>%
    distinct(value) %>%
    mutate(allvar2 = paste0(allvar, c("", "b")[1:n()])) %>% # Name duplicated variables, ex: var3, var3b
    # OP gets error using n(); use length(value) instead
    ungroup() %>%
    select(-allvar) %>%
    spread(allvar2, value, convert = TRUE) %>% # Make sure spread converts variables appropriately
    rbind_list(.,dat[is.na(dat$email),]) # rbind rows with missing email

Source: local data frame [3 x 7]

              email twitter var1 var2 var3 var3b var4
1 user1@hotmail.com   user1    2    1   NA    NA    0
2   user2@gmail.com   user2   NA    3    1     0   NA
3                NA   user3    1    1    2    NA   NA

【讨论】:

  • +1 表示tidyr 解决方案。我自己还没有尝试过,但我喜欢这个外观。
  • 感谢您的回答。我把我的例子讲得更清楚了。我用我的数据进行了测试,但它给我留下了变量“电子邮件”和所有 X 作为观察结果......我试图找出原因。
  • 我看到推特可能令人困惑......它只是一个变量。我在示例中对其进行了编辑。我正在尝试运行代码
  • 我得到这个:“错误:索引超出范围此外:有 50 个或更多警告(使用 warnings() 查看前 50 个)”?你知道是什么原因造成的吗?
  • @aosmith 当我使用您的数据集时,我得到这个“n() 中的错误:不应直接调用此函数另外:警告消息:属性在度量变量中不相同;它们将被删除"
猜你喜欢
  • 1970-01-01
  • 2011-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-18
  • 1970-01-01
  • 2016-05-14
相关资源
最近更新 更多