Выберите людей, которые находятся в нескольких группах в г - PullRequest
0 голосов
/ 30 сентября 2018

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

user <- c("User1", "User2", "User1", "User3","User4", 
          "User5", "User3", "User6", "User7", "User8", "User5")
place <- c("PlaceA", "PlaceA", "PlaceB", "PlaceB", "PlaceC", 
           "PlaceC", "PlaceC", "PlaceC", "PlaceD", "PlaceD", "PlaceD")
users_df <- data.frame(user, place)

Мне нужно что-то, что позволяет мне определить, какие пользователи входят в более чем одну конкретную группу, например:

  • , какие пользователи находятся в PlaceA, которые также находятся в PlaceB, или
  • , которые находятся в PlaceB и PlaceC и PlaceD, или
  • , какие пользователинаходятся в [PlaceB И (PlaceC ИЛИ PlaceD)]?

В идеале я хотел бы объединить соответствующие строки в отдельный кадр данных, чтобы в этом первом примереновый фрейм данных будет выглядеть так:

User1   PlaceA
User1   PlaceB

Но в отличие от данных здесь, фактические данные содержат около 25 000 наблюдений, еще несколько переменных и около 5000 уникальных имен людей, которые могут встречаться до 43группы / места.

Я пробовал разные варианты использования unique, %in%, which и str_which, но я просто полностью потерян ... Есть идеи?

Ответы [ 2 ]

0 голосов
/ 30 сентября 2018

Было бы лучше создать ваши данные следующим образом (тот же результат, но вы не получите случайные именованные векторы в вашей глобальной среде):

 users_df <- data.frame(
 user = c("User1", "User2", "User1", "User3","User4", "User5", "User3", "User6", "User7", "User8", "User5"),
 place  = c("PlaceA", "PlaceA", "PlaceB", "PlaceB", "PlaceC", "PlaceC", "PlaceC", "PlaceC", "PlaceD", "PlaceD", "PlaceD"))

Затем используйте базовую функцию splitу которого есть метод для фреймов данных:

group_by_user <- split(users_df, users_df$user)
group_by_user  #output not included

 sapply( group_by_user, function(df) length( unique(df$place) ) )
User1 User2 User3 User4 User5 User6 User7 User8 
    2     1     2     1     2     1     1     1 

Альтернативное использование, если требуется счетчик place:

> grouped_data <- split(users_df, users_df$place)
> grouped_data
$PlaceA
   user  place
1 User1 PlaceA
2 User2 PlaceA

$PlaceB
   user  place
3 User1 PlaceB
4 User3 PlaceB

$PlaceC
   user  place
5 User4 PlaceC
6 User5 PlaceC
7 User3 PlaceC
8 User6 PlaceC

$PlaceD
    user  place
9  User7 PlaceD
10 User8 PlaceD
11 User5 PlaceD

Затем вы можете выбрать place имя, например так:

> grouped_data[['PlaceB']]
   user  place
3 User1 PlaceB
4 User3 PlaceB

Или вы можете перебрать список информационных фреймов следующим образом:

lapply( grouped_data, nrow)
$PlaceA
[1] 2

$PlaceB
[1] 2

$PlaceC
[1] 4

$PlaceD
[1] 3


> sapply( grouped_data, nrow)
PlaceA PlaceB PlaceC PlaceD 
     2      2      4      3 
0 голосов
/ 30 сентября 2018
library(dplyr)
users_df %>% group_by(user) %>% filter(n() > 1)

Это даст вам то, что вы хотите --- обратите внимание, что вы группируете по user и получаете все экземпляры, где имеется более одного экземпляра.

Позвольте мне шаг за шагом привести вас к вашему окончательному выводу (что также проясняет для меня). Теперь, как и в вашем комментарии, если вам не безразличны пользователи, которые появляются несколько раз в одной группе,это просто изменится на

users_df %>% 
  group_by(user) %>%
  filter(n() > 1) %>% 
  group_by(user, place) %>% 
  filter(n() == 1)

Если вы более конкретно относитесь к своим условиям, например, пользователи, которые находятся в A & B:

## Use the `filter(n() == 1)` as necessary
users_df %>% 
  group_by(user) %>%
  dplyr::filter(place %in% c("PlaceA", "PlaceB")) %>%
  filter(n() > 1) 

Случай в вашем последнем комментарии: в(A & B) |(C & D & E).Это кажется сложным, но мы можем проявить творческий подход с lapply.

lapply(
  list(
    paste0("Place", c("A", "B")),
    paste0("Place", c("C", "D", "E"))
  ), function(x)
    users_df %>%
    group_by(user) %>%
    filter(place %in% c(x)) %>%
    filter(n() == length(x) & n() > 1)
) %>% 
  bind_rows()

Комбинация приведенного выше кода может получить то, что вы хотите.

...