Как построить вложенный цикл в R - PullRequest
0 голосов
/ 18 декабря 2018

Я использую R для сопоставления имен в двух разных наборах данных.Я хотел бы сравнить строки.У меня есть в основном два фрейма данных строк, оба содержат идентификатор местоположения (не уникальный), а также полные имена людей.Один фрейм данных имеет полные имена, которые могут содержать две фамилии, для некоторых людей.Другой фрейм данных имеет тот же код местоположения (не уникальный), но фамилии будут иметь только один из двух (всегда случайный, какой из двух).

Что я хочу сделать, это сделать grep(), строка за строкой первого фрейма данных, чтобы получить результаты поиска второго.Мой способ сделать это - сделать следующее:

  1. , используя функцию paste(), вставить идентификатор местоположения и имя.Это поможет с соответствием.Но мне действительно нужно сопоставить фамилию (может быть любая из фамилий).Давайте назовем этот новый вектор location_first

  2. и используем функцию strsplit() в столбце фамилии.Некоторые элементы списка будут иметь только один элемент, в то время как другие (т.е. лица с двумя фамилиями) будут иметь два элемента в этом элементе.Мы можем назвать этот список strsplit_ln.

  3. Затем я сделал бы вторую вставку в форме цикла: вставьте первый элемент strsplit_ln с помощью location_first, выполните grep, затем перейдите кследующий элемент strplit_ln и сделайте grep на этом.Я хочу распечатать все результаты поиска grep на моей консоли в текстовом файле.

Вот пошаговый процесс того, что я хотел бы сделать в форме цикла (или вложенного цикла)

# prepare the test data
names_df1 = data.frame(location = c(1530, 6801, 1530, 6801, 1967),
                       first_name = c("Axel", "Bill", "Carlos", "Flavio", "Jong"),
                       last_name = c("Williams", "Johnson Clarke", "Lopez Gutierrez",  "Mar", "Yoon"), stringsAsFactors = F)

names_df2 = data.frame(location = c(1530, 6801, 1530, 6801, 1967),
                       first_name = c("Axel", "Bill", "Carlos", "Flavio", "Jong"),
                       last_name = c("Williams", "Clarke", "Lopez", "Mar", "Yoon"), stringsAsFactors = F)


# Step 1: paste id and first name. Location ID and First Name are identical in both data frames. I will paste the last name in the second step. 
location_name_df1 = paste(names_df1$location, names_df1$first_name)
location_name_df2 = paste(names_df2$location, names_df2$first_name, names_df2$last_name)


# Step 2: string split the last names in df1. I want a loop to go through each element and subelement of this list. 
last_name_strsplit = strsplit(names_df1$last_name, split = " ")


          # these are what I would be searching. Note that in the loop, I go search through each sub element v of the ith element in the list.
          # paste(location_name_df1[i], last_name_strsplit[[i]][v])
          paste(location_name_df1[1], last_name_strsplit[[1]][1])

          paste(location_name_df1[2], last_name_strsplit[[2]][1])
          paste(location_name_df1[2], last_name_strsplit[[2]][2])

          paste(location_name_df1[3], last_name_strsplit[[3]][1])
          paste(location_name_df1[3], last_name_strsplit[[3]][2])

          paste(location_name_df1[4], last_name_strsplit[[4]][1])

          paste(location_name_df1[5], last_name_strsplit[[5]][1])


    # this is the actual search I would like to do. I paste the location_name_df1 with the last names in last_name_strsplit, going through each element (i), as well as each sub element (v)
    names_df1[grep(paste(location_name_df1[1], last_name_strsplit[[1]][1]),location_name_df2),] # search result successful

    names_df1[grep(paste(location_name_df1[2], last_name_strsplit[[2]][1]),location_name_df2),] # search result NOT successful. Note that this part of the list has two elements. Loop should jump to the second sub element of last_name_strplit
    names_df1[grep(paste(location_name_df1[2], last_name_strsplit[[2]][2]),location_name_df2),] # This search result was successful

    names_df1[grep(paste(location_name_df1[3], last_name_strsplit[[3]][1]),location_name_df2),] # search result successful
    names_df1[grep(paste(location_name_df1[3], last_name_strsplit[[3]][2]),location_name_df2),] # search result NOT successful. Note that this part of the list has two elements. End of sub elements, move on to the next row

    names_df1[grep(paste(location_name_df1[4], last_name_strsplit[[4]][1]),location_name_df2),] # search result successful

    names_df1[grep(paste(location_name_df1[5], last_name_strsplit[[5]][1]),location_name_df2),] # search result successful

Я довольноЯ уверен, что мне нужно сделать структуру вложенного цикла, где я прохожу каждый элемент списка (i), затем каждый его подэлемент (v).Однако, когда я делаю вложенный цикл, обычно происходит дублирование вставки, а сам поиск идет не так, как надо.

Может кто-нибудь дать мне несколько советов о том, как создать структуру цикла с вышеуказанными шагами?Я снова использую R / RStudio для сопоставления данных.

Спасибо!

1 Ответ

0 голосов
/ 18 декабря 2018

Вот более простой подход.Сначала мы выполняем полное объединение как местоположения, так и имени, затем используем stringr::str_detect (который, в отличие от grep, векторизован как для строки , так и шаблона), чтобы отфильтровать строки, где последний единственныйфамилия не является одной из двух возможных фамилий:

full = merge(names_df1, names_df2, by = c("location", "first_name"))

library(stringr)
matches = full[str_detect(string = full$last_name.x, pattern = fixed(full$last_name.y)), ]
matches           
#   location first_name     last_name.x last_name.y
# 1     1530       Axel        Williams    Williams
# 2     1530     Carlos Lopez Gutierrez       Lopez
# 3     1967       Jong            Yoon        Yoon
# 4     6801       Bill  Johnson Clarke      Clarke
# 5     6801     Flavio             Mar         Mar

Если вы предпочитаете dplyr, вы можете сделать это следующим образом:

library(dplyr)
full_join(names_df1, names_df2, by = c("location", "first_name")) %>% 
  filter(str_detect(string = last_name.x, pattern = fixed(last_name.y))
...