R

时间:2019-05-31 17:20:24

标签: r conditional-statements

我有一个由几列已知/预期结果组成的data.frame,并希望将它们与结构相同但结果可能不同的第二个data.frame进行比较。有四种可能的情况:

  • TruePositive(TP)==已知/观测向量的元素包含相同的信息,并且都不是NA
  • TrueNegative(TN)==已知/观测向量的元素均为NA
  • FalsePositive(FP)==已知是NA,而观察到的是一些nonNA值
  • FalseNegative(FN)==已知是一些nonNA值,观察到的是NA

我想生成一个新的data.frame,它对已知/观察到的data.frames中的每一列都评估这四个条件

我遇到过描述向量中多个条件的帖子,但是我没有看到任何有关比较两个共享相同索引(在R中)的向量元素的信息。

为了简单起见,我们有一对地图:“真实”地图是我们期望的,而“观察”地图是我们记录的。对于这两个地图,这些观测值都发生在相同的位置,并且每个位置都分为三部分(国家,地区和区域)。

true_map <- data.frame(
  MapSection = paste0("mapsection", seq(1:5)),
  Country = c(rep("Canada", 3), rep("UnitedStates", 2)),
  Region = c(rep("Ontario", 3), "NewYork", "Alaska"),
  Zone = c("Toronto", "Ottawa", NA, "Albany", NA)
)

obsrvd_map <- data.frame(
  MapSection = paste0("mapsection", seq(1:5)),
  Country = c(rep("Canada", 3), rep("UnitedStates", 2)),
  Region = c(rep("Ontario", 2), NA, "NewYork", "Alaska"),
  Zone = c("Toronto", "Ottawa", NA, "Albany", "Fairbanks")
)

Country级别,真实地图和观察到的地图是相同的。但是,在Region级别,mapsection3在“已观察”地图(NA)中缺少信息,而“ true”地图具有位置(Ontario)。这将被归类为FalseNegative,因为我们缺少期望的信息。 相反,mapsection5在Zone级别的“ true”映射中缺少信息,而“ observed”映射包含信息(Fairbanks)。这将被归类为FalsePositive,因为在我们不希望获得信息的地方还有其他信息。但是,“真实”和“观察”地图在mapsection3的Zone级别都缺少信息。这将被视为TrueNegative,因为两者都缺少信息。

最终结果将这些观察总结如下:

MapSection Country Region Zone
mapsection1      TP     TP   TP
mapsection2      TP     TP   TP
mapsection3      TP     FN   TN
mapsection4      TP     TP   TP
mapsection5      TP     TP   FP

谢谢您的协助!

2 个答案:

答案 0 :(得分:1)

您的答案中的逻辑看起来很扎实,但还没有扩展到您需要的其他组合。为此,我将数据重整为长格式,以便您有一列地理级别和一个区域。

library(dplyr)
library(tidyr)

true_map_long <- true_map %>%
  gather(key = level, value = value, -MapSection)
obsrvd_map_long <- obsrvd_map %>%
  gather(key = level, value = value, -MapSection)

两者的形状如下:

head(true_map_long)
#>    MapSection   level        value
#> 1 mapsection1 Country       Canada
#> 2 mapsection2 Country       Canada
#> 3 mapsection3 Country       Canada
#> 4 mapsection4 Country UnitedStates
#> 5 mapsection5 Country UnitedStates
#> 6 mapsection1  Region      Ontario

按地图部分和级别加入这两个长形表,并提供适当的后缀以使其更清楚。 case_when本质上是相同的,但是现在您不再局限于一个位置。

joined <- inner_join(
  true_map_long,
  obsrvd_map_long,
  by = c("MapSection", "level"),
  suffix = c("_t", "_o")
) %>%
  mutate(truth = case_when(
    value_t == value_o  ~ "TP",
    is.na(value_t) == is.na(value_o)  ~ "TN",
    is.na(value_t) & !is.na(value_o)  ~ "FP",
    !is.na(value_t) & is.na(value_o)  ~ "FN",
  ))
head(joined)
#>    MapSection   level      value_t      value_o truth
#> 1 mapsection1 Country       Canada       Canada    TP
#> 2 mapsection2 Country       Canada       Canada    TP
#> 3 mapsection3 Country       Canada       Canada    TP
#> 4 mapsection4 Country UnitedStates UnitedStates    TP
#> 5 mapsection5 Country UnitedStates UnitedStates    TP
#> 6 mapsection1  Region      Ontario      Ontario    TP

然后放置值列,并再次扩展为宽形状。您可以一步一步地完成并加入;分为两部分更容易解释。

joined %>%
  select(-starts_with("value")) %>%
  spread(key = level, value = truth)
#>    MapSection Country Region Zone
#> 1 mapsection1      TP     TP   TP
#> 2 mapsection2      TP     TP   TP
#> 3 mapsection3      TP     FN   TN
#> 4 mapsection4      TP     TP   TP
#> 5 mapsection5      TP     TP   FP

reprex package(v0.3.0)于2019-05-31创建

答案 1 :(得分:0)

按照布鲁斯的建议,我只提取了一个位置类型,并尝试评估了我描述的四个条件。我认为它在起作用...

Zone_df <- merge(true_map[,c("Zone", "MapSection")], obsrvd_map[,c("Zone", "MapSection")], by="MapSection") %>% 
  rename(., exp.Zone=Zone.x, obs.Zone=Zone.y) %>% 
  mutate_if(is.factor, as.character)

Zone_df %>% 
  mutate(EvalCase = case_when(
    (exp.Zone) == (obs.Zone)  ~ "TP",
    is.na(exp.Zone) == is.na(obs.Zone)  ~ "TN",
    is.na(exp.Zone) & !is.na(obs.Zone)  ~ "FP",
    !is.na(exp.Zone) & is.na(obs.Zone)  ~ "FN",
))