通过在r中部分匹配另一个数据帧来细分数据帧(对python/pandas解决方案开放)

2024-10-01 07:34:02 发布

您现在位置:Python中文网/ 问答频道 /正文

基本问题描述:

df为数据帧,df_match为单行数据帧。在

我想对df进行子集化,以便只保留其非NA值包含在df_match的非NA值中的行。在

一个最小的例子:

df <- data.frame(A = c("a1", "a1", "a2", NA, "a1", "a1"), 
             B = c(NA,"b1", "b1", "b2", "b1",NA), 
             C = c(NA,NA,NA,NA,"c1","c1"),
             D = c(NA,NA,NA,NA,"d1","d1"),
             stringsAsFactors = FALSE)

# column D is not nessecary I imputed it to get a data frame when applying is.na() below

df_match <- data.frame(A= "a1", 
                       B = "b1", 
                       C = NA,
                       D = NA,
                   stringsAsFactors = FALSE)


     A    B    C    D
1   a1 <NA> <NA> <NA>
2   a1   b1 <NA> <NA>
3   a2   b1 <NA> <NA>
4 <NA>   b2 <NA> <NA>
5   a1   b1   c1   d1
6   a1 <NA>   c1   d1

> df_match
   A  B  C  D
1 a1 b1 NA NA

在最小的例子中,只有df的前两行是正确的w.r.t.“部分匹配”。在

^{pr2}$

第3行和第4行在a列或B列中输入错误

第5个和第6个在df_match中不支持的列中包含一个值(即在df\u match中具有非NA值的列)。在

     A    B    C    D
1   a2   b1 <NA> <NA>
2 <NA>   b2 <NA> <NA>
3   a1   b1   c1   d1
4   a1 <NA>   c1   d1

基本思路:

df的每一行与df_match匹配,并将结果存储到一个布尔矩阵M。在

然后创建一个按行号索引的布尔向量,如下所示:TRUE if

1)在M上支持df_match的列(即在dfˉmatch中具有非NA值的列)不包含false。在

2)在df_match中不支持的M列不包含TRUE

我目前对最小示例的解决方案:

df <- data.frame(A = c("a1", "a1", "a2", NA, "a1", "a1"), 
             B = c(NA,"b1", "b1", "b2", "b1",NA), 
             C = c(NA,NA,NA,NA,"c1","c1"),
             D = c(NA,NA,NA,NA,"d1","d1"),
             stringsAsFactors = FALSE)

# column D is not nessecary I imputed it to get a data frame when applying is.na() below

df_match <- data.frame(A= "a1", 
                       B = "b1", 
                       C = NA,
                       D = NA,
                   stringsAsFactors = FALSE)


library(dplyr)

# create a boolean vector for condition 2
not_matchable <- names(df_match)[is.na(df_match)]
bol_no_matchable <- df %>%
      select(one_of(not_matchable)) %>%
      is.na() %>%
      apply(X = ., MARGIN = 1, any)

# create a boolean vector for condition 1
matchable <- names(df_match)[!is.na(df_match)]
bol_matchable <- sapply(1:nrow(df), function(row)
    {
    df[row,matchable] != df_match[,matchable]
  }) %>%
    apply(X = ., MARGIN = 2, FUN = any)

bol_matchable[is.na(bol_matchable)] <- FALSE 

# filter the results
df <- df %>%
   filter(!bol_matchable & bol_no_matchable)

问题:

  • 我可以遵循哪些一般原则来提高子集问题的性能?在
  • 如何提高以上代码的性能?在
  • 关于我的实际问题,我如何改进下面代码的性能?在

问题: 在应用程序中,数据框df有一个列X,其中df可以有df_match之外的值。(见下文)

应用基本最小示例中的逻辑,我当前的解决方案如下:

df <- data.frame(A = c("a1", "a1", "a2", NA, "a1", "a1"), 
                 B = c(NA,"b1", "b1", "b2", "b1",NA), 
                 C = c("c2",NA,"c1",NA,"c1","c1"),
                 D = c(NA,"d2","d2","d2","d1","d1"),
                 X = c("C","D","C","D","D","C"),
                 stringsAsFactors = FALSE)

bol <- sapply(1:nrow(df), function(x)
{
  # determine value in column X
  X <- pull(df[x,], "X")
  not_matchable <- setdiff(matchable, X)
  # create boolean vector for condition 1)
  bol_no_matchable <- df[x,] %>%
    select(one_of(not_matchable)) %>%
    is.na() %>%
    all()

  # create boolean vector for condition 2)
  bol_matchable <- {df[x,not_matchable] != df_match[,not_matchable]} 
  bol_matchable[is.na(bol_matchable)] <- FALSE
  bol_matchable <- any(bol_matchable)

  # combine both conditions
  bol <- !bol_matchable & bol_no_matchable
})

上面的代码没有我想要的那么快。因为我想将这个“函数”应用到一个数据帧df,其中有~50m行和100+列,用于任意数据帧df_match。在

因此,欢迎对不同方法的任何建议/想法以及对子分组的评论。在


Tags: falsedfdataisa1matchnotframe
1条回答
网友
1楼 · 发布于 2024-10-01 07:34:02

您可以在df和{}的列上Map,如果{}的对应元素是NA或等于df_match的元素,则为每一列对返回一个元素为TRUE的向量。然后选择TRUE的数目(由rowSums生成)等于列数的行(即所有列要么匹配要么都是NA)。在

注意:如果df_match值是NA,而df值是非NA,则{}输出的相应向量元素将是NA,当与na.rm = TRUE一起使用{}时,它与FALSE等价

row_matches <- 
  rowSums(mapply(function(x, y)  is.na(x) | x == y, df, df_match),  na.rm = TRUE)

df[row_matches == ncol(df),]
#    A    B    C    D
# 1 a1 <NA> <NA> <NA>
# 2 a1   b1 <NA> <NA>

相关问题 更多 >