【问题标题】:Data Validation: Checking Real Data Based on Benchmark Data数据验证:基于基准数据检查真实数据
【发布时间】:2019-02-04 14:22:17
【问题描述】:

我有一个包含姓名、国籍和性别等变量的数据集。我想检查该数据集的性别变量的正确性,该基准数据集包含每个姓名-国籍-组合的正确性别值。

考虑以下两个示例数据集:

# Real data set that should be validated
df_real <- data.frame(name = c("Kevin", "Marie", "Rute", NA, "Charles", "Bruno"),
                      nationality = c("USA", "DE", "PT", "FR", NA, "PT"),
                      sex = c(1, 2, 1, 2, 2, NA)) # 1 = Male; 2 = Female

# Correct data set as basement for validation
df_check <- data.frame(name = c("Alfons", "Kevin", "Kevin", "Kevin", "Rute", "Charles", "Bruno", "Anne"),
                       nationality = c("FR", "USA", "DE", "PT", "PT", "FR", "PT", "LU"),
                       sex = c(1, 1, 1, 1, 2, 1, 1, 2))

df_real 的列sex 应根据df_check 检查正确性。在示例中,第三行旁边的所有性别值都是正确的(即 Rute 应该是 df_real 中的女性)。

需要考虑几个额外的数据条件:

  • df_real 有几个 NA。如果df_real 中某行的任何值为NA,则应跳过该行的检查。
  • 出现在df_real 中的名称并不总是出现在df_check 中。在这种情况下,也应跳过对该行的检查。

最终输出应该是一个长度为nrow(df_real)的虚拟向量,包含0(即值正确或跳过检查)和1(即值不正确)。

预期输出:

output_check <- c(0, 0, 1, 0, 0, 0)

我试图用复杂的 for 循环和 if 条件来解决这个问题。但是,由于我的数据非常大,这需要大量的计算时间。我确信必须有一个基于 apply() 函数的更简单的解决方案,但遗憾的是我无法弄清楚。

【问题讨论】:

  • 你需要library(data.table);setDT(df_real)[df_check, flag := 1, on = names(df_real)];df_real[is.na(flag), flag := 0]
  • @akrun 感谢您的评论。如果我运行您的代码,我会收到标志 c(1, 0, 0, 0, 0, 0),但它应该是 c(0, 0, 1, 0, 0, 0)

标签: r validation dataframe


【解决方案1】:

我们可以使用data.table 对“姓名”、“国籍”进行连接以创建“检查”列

library(data.table)
setDT(df_real)[df_check, check :=  +(sex !=  i.sex), on = .(name, nationality)]
df_real[is.na(check), check := 0]
df_real
#      name nationality sex check
#1:   Kevin         USA   1     0
#2:   Marie          DE   2     0 
#3:    Rute          PT   1     1
#4:    <NA>          FR   2     0
#5: Charles        <NA>   2     0
#6:   Bruno          PT  NA     0

【讨论】:

  • 非常感谢,正是我想要的。
  • @JSP 没问题。我假设您的原始数据中不需要任何 sex.xsex.y
【解决方案2】:

我们可以left_joinnamenationality 上的两个表然后检查sex 列并分配值1,以防它们是不同的值,replace 不匹配NAs 0.

library(tidyverse)

df_real %>% 
  left_join(df_check, by = c("name" = "name","nationality" = "nationality")) %>%
  mutate(check = +(sex.x != sex.y)) %>%
  replace_na(list(check = 0)) #%>%
  #select(-sex.x, -sex.y) #if you don't need sex columns


#     name nationality sex.x sex.y check
#1   Kevin         USA     1     1     0
#2   Marie          DE     2    NA     0
#3    Rute          PT     1     2     1
#4    <NA>          FR     2    NA     0
#5 Charles        <NA>     2    NA     0
#6   Bruno          PT    NA     1     0

使用与基础 R 相同的逻辑merge

df1 <- merge(df_real, df_check, by = c("name", "nationality"), all.x = TRUE)
df1$check <- +(df1$sex.x != df1$sex.y)
df1$check[is.na(df1$check)] <- 0

df1
#     name nationality sex.x sex.y check
#1   Bruno          PT    NA     1     0
#2 Charles        <NA>     2    NA     0
#3   Kevin         USA     1     1     0
#4   Marie          DE     2    NA     0
#5    Rute          PT     1     2     1
#6    <NA>          FR     2    NA     0

输出的显示顺序在基础 R 中有所不同。

【讨论】:

  • 非常感谢!我将使用 tydiverse 解决方案,但两种解决方案都完全符合我的要求。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-09
  • 2020-11-23
  • 2018-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多