Проверьте строку в dataframe, содержащем список строк - PullRequest
0 голосов
/ 11 июля 2019

Я пытаюсь найти способ поиска нескольких значений в кадре данных и вернуть значение.Упрощенный пример:

df1 <- read.table(text="chk1    chk2    chk3    value
xx  aa;bb;cc    jj  1
xx;yy   dd;ee;ff    kk  2
zz  gg;hh;ii    ll;nn   3", header=T)

df2 <- read.table(text="val1    val2    val3
xx  bb  jj
xx  dd  kk
yy  ee  kk
zz  hh  jj
", header=T)

Поиск значений val1, val2 и val3 из df2 в df1, возвращаемое значение из df1.

Желаемые результаты:

df2 <- read.table(text="
                  val1  val2    val3    value
xx  bb  jj  1
xx  dd  kk  2
yy  ee  kk  2
zz  hh  jj  NA
")

Пробовал match x %in% y и циклически перебирал строки, не мог заставить его работать.

Ответы [ 3 ]

0 голосов
/ 11 июля 2019

другой вариант будет сначала разбивать значения:

df1 <- df1 %>% 
    splitstackshape::cSplit("chk1", ";", fixed = TRUE, direction = "long", drop = FALSE, type.convert = FALSE) %>% 
    splitstackshape::cSplit("chk2", ";", fixed = TRUE, direction = "long", drop = FALSE, type.convert = FALSE) %>% 
    splitstackshape::cSplit("chk3", ";", fixed = TRUE, direction = "long", drop = FALSE, type.convert = FALSE) 

, а затем с помощью соединения

0 голосов
/ 11 июля 2019

Вы также можете сделать это, используя два вложенных цикла for.Логика состоит в том, чтобы взять первую строку df2, а затем начать проходить по строкам df1, чтобы увидеть, соответствует ли df2$val1 df1$chk, df2$val2 соответствует df1$chk2 и df2$val3 соответствует df1$chk3.Я считаю, что все значения совпадают, если в каждом столбце есть хотя бы одно совпадение.Каверат здесь заключается в том, что если df2 не имеет уникальных строк, последняя соответствующая строка из df1 будет записана в df2.Но это можно изменить, разорвав цикл, как только совпадение будет найдено.

for (i in 1:nrow(df2)) {
  for (j in 1:nrow(df1)) {
    # Take i-th row and split by ;. Result is a vector of strings against
    # which we'll use match.
    i.split <- strsplit(as.character(unlist(df1[j, , drop = TRUE][-4])), ";")
    # Pairwise check columns from df1 and df2.
    all.ok <- all(mapply(FUN = function(x, y) {
      any(x %in% y)
    }, x = i.split, y = as.list(df2[i, 1:3])
    ))

    if (all.ok) {
      # If a match is found, write the value to df2.
      df2[i, "value"] <- df1[j, "value"]
    }
  }
}

Вывод:

  val1 val2 val3 value
1   xx   bb   jj     1
2   xx   dd   kk     2
3   yy   ee   kk     2
4   zz   hh   jj    NA
0 голосов
/ 11 июля 2019

Вот одна из возможностей:

library(tidyverse)
df3 <- df2 %>% rowwise %>% 
       mutate(rowmatch=which(grepl(val1, df1$chk1) & 
                             grepl(val2, df1$chk2) & 
                             grepl(val3, df1$chk3))[1], 
              value=df1$value[rowmatch])

Результат:

# A tibble: 4 x 5
  val1  val2  val3  rowmatch value
  <chr> <chr> <chr>    <int> <int>
1 xx    bb    jj           1     1
2 xx    dd    kk           2     2
3 yy    ee    kk           2     2
4 zz    hh    jj          NA    NA

Примечания:

  • [1] должен гарантировать, что только первый изиспользуются соответствующие строки.
  • обратите внимание, что хотя rowmatch и value идентичны в этом примере, это только потому, что df1$value равен номеру строки.
  • tibbleведет себя как data.frame, но если вы действительно предпочитаете фрейм данных, добавьте %>% as.data.frame

То же самое можно сделать с базой R и применить:

df2$rowmatch <- with(df1, apply(df2, 1, function(x) 
    which(grepl(x["val1"], chk1) & 
          grepl(x["val2"], chk2) & 
          grepl(x["val3"], chk3))[1]))

df2$value <- df1$value[df2$rowmatch]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...