R - Как классифицировать каждую строку в кадре данных в зависимости от частичного соответствия с другим кадром данных? - PullRequest
0 голосов
/ 08 мая 2018

У меня есть два кадра данных (df1 и df2), вот df1:

SAMPLE NAMES
1_a
1_b
1_c
2_a
2_b
3_a
4_a
4_b

Вот df2:

ID  GROUP   
1   X
2   X
3   Y
4   Z

Вот что я хочу сделать - я хочу добавить новый столбец в df1, который будет указывать группу образца, основываясь на частичном совпадении со столбцом ID в df2. Поэтому выборки "2_a" и "2_b" из df1 должны иметь ту же группу, что и "2" в df2.

Желаемый вывод:

SAMPLE NAMES    GROUP
1_a             X
1_b             X
1_c             X
2_a             X
2_b             X
3_a             Y
4_a             Z
4_b             Z

До сих пор я пытался использовать пакет stringr и написать цикл for:

for (i in df1[, 1]){
  for (j in df2$ID){
    x <- which(str_detect(i,j))
    class <- df2[j,1]
    df1$group[i] <- class
  }
}

но он продолжает давать мне ошибку:

Error in UseMethod("type") : 
  no applicable method for 'type' applied to an object of class "c('integer', 'numeric')"

Что я сделал не так? Кроме того, есть ли способ сделать это, используя функцию apply () вместо циклов?

Ответы [ 3 ]

0 голосов
/ 08 мая 2018

Основная причина, по которой ваш цикл for не работает, заключается в том, что str_detect() принимает только строки в качестве входных данных, но вы пытаетесь использовать его в столбце идентификатора в df2, который является числовым вектором.Есть и другие проблемы с вашим циклом for: в частности, вы определяете объект x, который фактически никогда не используется впоследствии, и поэтому ваш код не будет выбирать элементы, которые вы хотите использовать, используя str_detect().

* 1006.* Вот еще один вариант, если вы хотите больше stringr решения.Он не использует ни циклы for, ни apply() (по крайней мере, напрямую).

Он работает с использованием регулярных выражений для извлечения только числовых символов из столбца «SAMPLE.NAMES», чтобы связать каждый образец с его числовымЯ БЫ.После этого мы просто объединяем кадры данных и выбираем нужные вам столбцы:

# Example dataframes
df1 <- tibble(SAMPLE.NAMES = c("1_a", "1_b", "1_c", "2_a", "2_b", "3_a", "4_a", "4_b"))
df2 <- tibble(ID = c(1,2,3,4),
              GROUP = c("X", "X", "Y", "Z"))

df1 <- mutate(df1, ID = as.numeric(str_replace_all(SAMPLE.NAMES, "_[abc]", ""))) %>%
       left_join(df2) %>%
       select(-ID)

# Output:
# A tibble: 8 x 2
  SAMPLE.NAMES GROUP
  <chr>        <chr>
1 1_a          X    
2 1_b          X    
3 1_c          X    
4 2_a          X    
5 2_b          X    
6 3_a          Y    
7 4_a          Z    
8 4_b          Z  
0 голосов
/ 08 мая 2018

Просто объедините часть строки перед подчеркиванием:

> df1$ID <- sub("_.+$","",df1$SAMPLENAMES)
> df1
  SAMPLENAMES ID
1         1_a  1
2         1_b  1
3         1_c  1
4         2_a  2
5         2_b  2
6         3_a  3
7         4_a  4
8         4_b  4
> merge(df1,df2, by="ID")
  ID SAMPLENAMES GROUP
1  1         1_a     X
2  1         1_b     X
3  1         1_c     X
4  2         2_a     X
5  2         2_b     X
6  3         3_a     Y
7  4         4_a     Z
8  4         4_b     Z
0 голосов
/ 08 мая 2018

Вот вариант tidyverse

library(tidyverse)
df1 %>% 
 separate(., col = SAMPLE.NAMES, into = c('SAMPLE', 'NAMES'), sep = "_", convert = TRUE) %>% 
 left_join(df2, by = c('SAMPLE' = 'ID')) %>% 
 unite(., col = SAMPLE.NAMES, SAMPLE, NAMES)
#  SAMPLE.NAMES GROUP
#1          1_a     X
#2          1_b     X
#3          1_c     X
#4          2_a     X
#5          2_b     X
#6          3_a     Y
#7          4_a     Z
#8          4_b     Z

Сначала мы separate столбец 'SAMPLE.NAMES' из df1 пополам, так что мы можем left_join df1 с df2 по 'SAMPLE' и 'ID'. В последней строке мы unite возвращаем столбцы «SAMPLE» и «NAME» в «SAMPLE.NAMES».

Данные

df1 <- structure(list(SAMPLE.NAMES = structure(1:8, .Label = c("1_a", 
"1_b", "1_c", "2_a", "2_b", "3_a", "4_a", "4_b"), class = "factor")), .Names = "SAMPLE.NAMES", class = "data.frame", row.names = c(NA, 
-8L))

df2 <- structure(list(ID = 1:4, GROUP = structure(c(1L, 1L, 2L, 3L), .Label = c("X", 
"Y", "Z"), class = "factor")), .Names = c("ID", "GROUP"), class = "data.frame", row.names = c(NA, 
-4L))
...