r цикл / функция для поиска совпадений из списка

#r #list #function #loops

#r #Список #функция #циклы

Вопрос:

У меня есть список продавцов в трех столбцах, и я хочу перейти к списку, который у меня есть, и:
а) Где их имя отображается в любом из трех столбцов
б) их имя отображается с продавцом-стажером (это будут люди, чьего имени нет в списке)

 ilist <- c("SP1","SP2","SP3","SP4","SP5")
    
df2 <- 
    data.frame(sales1 = c("SP5","SP5","SP4","SP3","SP2","SP1","SP3"), 
               sales2 = c("","SP4","SP1","SP1","SP5","SP3",""), 
               sales3 = c("","SP9","","SP6","","",""))
  

Вывод Я бы ожидал чего-то вроде приведенного ниже ответа (хотя я бы принял любой вывод):

       A     B   
SP1   3     1 
SP2   1     0 
SP3   3     1 
SP4   1     1 
SP5   3     1
  

Я пытался создать цикл и функцию, но, похоже, я не могу заставить их работать.
Цель после запуска этой работы — сделать ее частью group_by , чтобы я мог разбить ее по типу и году

 data %>%
group_by(type,year) %>%
your helpful answer here
  

Редактировать:
select из столбцов, которые я собираюсь использовать.
Мой список будет выглядеть примерно так, как показано ниже
(в 3 столбцах столбцы 2 и 3 будут содержать пробелы, где продавец отображается только в столбце 1; также не задано место размещения, где может появиться продавец или стажер).

 ilist <- c("SJ","KW","MOLC","FERB","BACC")



structure(list(iYear = structure(c(1L, 4L, 3L, 4L, 4L, 
4L, 5L, 5L, 6L, 9L), .Label = c("2020-07-01", "2020-07-02", "2020-07-03", 
"2020-07-04", "2020-07-06", "2020-07-07", "2020-07-08", "2020-07-09", 
"2020-07-10", "2020-07-11", "2020-07-12", "2020-07-13", "2020-07-14", 
"2020-07-15", "2020-07-16", "2020-07-17", "2020-07-18", "2020-07-19", 
"2020-07-20", "2020-07-21", "2020-07-22", "2020-07-23", "2020-07-24", 
"2020-07-25", "2020-07-27", "2020-07-28", "2020-07-29", "2020-07-30", 
"2020-07-31"), class = "factor"), iType = structure(c(4L, 
4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L), .Label = c("", "ZB", "BS", 
"CFN", "CTR", "MJ", "UK", "EFH", "ENOC", "EY", "F", "G", "CD", 
"HAEM", "HN", "IC", "LB", "LY", "MNN", "MOS", "NERO", "ZZZ", 
"ZZZQE", "GFT", "PG", "RE", "SK", "UR"), class = "factor"), 
    Sales.1 = structure(c(74L, 20L, 74L, 16L, 
    3L, 3L, 3L, 16L, 58L, 41L), .Label = c("", "ABUE", "AHMEM", 
    "AJOS", "ANNS", "AOK", "BACC", "BH", "BLAFM", "BLOCA", "BRAD", 
    "BROWNJ", "BRT", "BUIH", "BURDA", "BURYA", "CANRJ", "CAVM", 
    "CHAMBA", "COOSNP", "COUPSI", "CPH", "CTT", "DARA", "DILP", 
    "EXPAT", "FCH", "FERB", "FERMA", "GT", "GT", "HAEM", "HAMJR", 
    "HENJ", "HENJA", "HOWRA", "HUSA", "ILINC", "JONG", "KC", 
    "KNOT", "KW", "LAUC", "LOOP", "LYEJO", "LYNN", "MAJJ", "MCGREA", 
    "MENT", "MKB", "MOLC", "MUDHS", "MULLM", "NC", "NODS", 
    "O'BSG", "OLIT", "OLIVK", "PAEI", "PARKD", "PATEF", "PERT", 
    "POL", "PTRHUS", "RAMACN", "RAMS", "REYMA", "ROBCM", "ROBINE", 
    "SAMJN", "SAYC", "SHARMM", "SHEG", "SJ", "SJN", "SKINT", 
    "SLOP", "SORT", "SOUBIO", "SPOE", "TELED", "THAN", "THEL", 
    "TURH", "TURHJ", "UCONS", "UPH", "UT", "VALK", "WALJ"
    ), class = "factor"), Sales.2 = structure(c(1L, 
    12L, 1L, 1L, 1L, 1L, 1L, 1L, 3L, 45L), .Label = c("", "ABUE", 
    "AHMEM", "AJOS", "AOK", "BACC", "BH", "BLAFM", "BROWNJ", 
    "BUIH", "BURDA", "BURYA", "CANRJ", "CAVM", "CHAMBA", "COOSNP", 
    "COUPSI", "DARA", "DILP", "FCH", "FERB", "FERMA", "GYNT", 
    "HOWRA", "HUSA", "ILINC", "KW", "LAUC", "LOOP", "LYNN", "MAJJ", 
    "MOLC", "MULLM", "NC", "OLIVK", "PARKD", "POL", "PTRHUS", 
    "RAMS", "REYMA", "ROBCM", "ROBINE", "SAMJN", "SHARMM", "SJ", 
    "SJN", "SKINT", "SLOP", "SORT", "SPOE", "TELED", "THAN", 
    "THEL", "TURH", "VALK"), class = "factor"), Sales.3 = structure(c(1L, 
    1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = c("", "AHMEM", 
    "AOK", "BACC", "BLAFM", "CHAMBA", "COUPSI", "DILP", "FCH", 
    "KW", "LOOP", "MAJJ", "PTRHUS", "RAMS", "ROBCM", "SAMJN", 
    "SHARMM", "SJ", "TELED", "THAN", "VALK"), class = "factor")), row.names = c(NA, 
10L), class = "data.frame")
  

Комментарии:

1. то, что вы хотите, не очень понятно. например, SP1 появляется в позиции 6 df2 $ sales1 и в позиции 3 и 4 df2 $ sales2. итак, когда вы указываете, где они отображаются в любом из столбцов, я бы предположил, что вы хотите, чтобы результаты для SP1 в столбце A были (3, 4, 6) . почему результат равен 3? также вы говорите, что хотите сгруппировать по типу и году … хорошо, но у вас нет столбца типа и года, поэтому неясно, чего вы пытаетесь достичь.

2. хм, вы хотите знать, в каких строках df2 данной продажи появляется стажер?

3. Обновлено с использованием текущих данных

4. Для чего iType используются ваши текущие данные? Игнорируется ли это в этом процессе? Используется ли это в «разбивке по типу и году»?

5. @Ben Тип — это Отдел / секция, к которому он принадлежит. Итак, этот период для этих разделов написан этим человеком.

Ответ №1:

Я не уверен, что это то, что вы ищете, но подумал, что это может быть полезно. С вашим интересом к использованию group_by звучит так, как будто вам может понадобиться tidyverse подход.

Здесь нужно добавить номера строк, чтобы вы могли group_by в каждой строке видеть, присутствует ли стажер с продавцом в одной строке.

Затем используйте pivot_longer для перевода в длинный формат и удаления пустых строк.

При группировании по номеру строки вы можете добавить индикатор того, что эти люди появятся у продавца-стажера. Он проверяет, не содержится ли человек в ilist .

Наконец, вы можете group_by каждого продавца включить только в ilist с filter и сложить количество появлений (предполагается, что только один раз в строке исходных данных) и количество контактов стажера.

 library(tidyverse)

df2 %>%
  mutate(rn = row_number()) %>%
  pivot_longer(cols = -rn) %>%
  na_if("") %>%
  na.omit %>%
  group_by(rn) %>%
  mutate(with_trainee = ifelse(any(!value %in% ilist), 1, 0)) %>%
  group_by(value) %>%
  filter(value %in% ilist) %>%
  summarise(A = n(),
            B = sum(with_trainee))
  

Вывод

   value     A     B
  <chr> <int> <dbl>
1 SP1       3     1
2 SP2       1     0
3 SP3       3     1
4 SP4       2     1
5 SP5       3     1
  

Редактировать 1: используя ваши «текущие данные» и группируя результаты по годам из iYear и iType , вы можете попробовать это:

 library(tidyverse)

df2 %>%
  mutate(rn = row_number(),
         iYear = substr(iYear, 1, 4)) %>%
  pivot_longer(cols = -c(rn, iYear, iType)) %>%
  na_if("") %>%
  na.omit %>%
  group_by(rn, iYear, iType) %>%
  mutate(with_trainee = ifelse(any(!value %in% ilist), 1, 0)) %>%
  group_by(value, iYear, iType) %>%
  filter(value %in% ilist) %>%
  summarise(A = n(),
            B = sum(with_trainee)) 
  

Редактирование 2: дополнительное подробное объяснение:

Номера строк ( rn через row_number ) полезны в этом случае, так как вы хотите знать, присутствуют ли продавцы в одно и то же время (что подразумевает «в пределах одной строки»). Итак, если 2 продавца используют одно и то же rn , они присутствовали в одно и то же время.

iYear изменен всего на год. Он использует substr() (substring) для взятия с 1-го по 4-й символ iYear , который в формате даты XXXX-XX-XX является годом.

pivot_longer (и его друг, pivot_wider ) действительно эффективны для преобразования из длинных <-> широких форматов данных. В tidyr пакете pivot_longer принимает все столбцы (кроме rn , iYear , и iType ) и помещает в два столбца ( name и value ). value теперь продавец содержится в одном столбце вместо нескольких столбцов, с которых он начинался.

na_if("") приведет к тому, что пустые строки "" станут NA (отсутствующие данные). Последующие na.omit действия удалят эти строки с NA помощью then.

Функция group_by with rn гарантирует, что вы смотрите коллективно на тех продавцов, которые разделяют то же rn самое . Я добавил iYear и iType , чтобы они также отображались в итоговых итоговых результатах. Затем with_trainee создается новый столбец, в котором будет указано, является ли этот продавец стажером или нет (после group_by использования any , чтобы увидеть, есть ли в векторе «любая строка» в группе, разделяющая одно и то же rn ilist ). Если есть, то кодируйте как 1, если нет, то кодируйте как 0.

Следующий group_by — by value (или продавец), используя filter , поскольку вам нужны результаты только для тех, кто находится внутри ilist . (Если вы хотите, чтобы все, включая отсутствующих стажеров, отсутствовали ilist , вы могли бы исключить эту строку.)

Финал summarise работает с group_by — with n() , показывая количество строк данных на value (или на одного продавца), которое совпадает с количеством различных rn значений, которые могут отображаться у продавца в целом. Это sum(with_trainee) общее количество раз with_trainee , когда значение было 1 для данного value (или продавца).

Вывод

   value iYear iType     A     B
  <fct> <chr> <fct> <int> <dbl>
1 SJ    2020  CFN       3     1
  

Комментарии:

1. Я добавил некоторые текущие данные, если это поможет

2. Пожалуйста, смотрите отредактированный ответ. Это берет год из iYear и группирует по году и iType . Это ближе к тому, что вам нужно?

3. Похоже, это работает, и это потрясающе. Огромная помощь. Глядя на то, что вы создали, мне еще предстоит пройти много миль. Если я правильно это читаю, вы: Добавили идентификационные номера потока > Сделали iYear всего на год> (Pivot_longer Мне нужно будет исследовать, поскольку я с этим не сталкивался) > Не применимо, если пусто > (нет.опустить, мне нужно исследовать) > Группировать по трем типам (число,год и тип)> Добавьте дополнительный столбец для значений, которых нет в моем списке, чтобы идентифицировать стажера; присвоив им 1> Фильтр по тому, что есть в моем списке> Выведите данные с количеством совпадений в списке и добавьте стажеров, правильно ли я это делаю?

Ответ №2:

Честно говоря, я не совсем понимаю ожидаемый результат, поскольку вы говорите, что ожидаете SP2 | 1 | 0 , но SP2 не появился в строке 1. следующее может делать то, что вы хотите … или нет.

 library(data.table)

sales <- data.table(sale = c("SP1", "SP2", "SP3", "SP4", "SP5"))

sales_group <- 
  data.table(
    sales1 = c("SP5", "SP5", "SP4", "SP3", "SP2", "SP1", "SP3"),
    sales2 = c("", "SP4", "SP1", "SP1", "SP5", "SP3", ""),
    sales3 = c("", "SP9", "", "SP6", "", "", "")
  )

all <- sort(sales_group[, unique(c(sales1, sales2, sales3))])
all <- all[all != ""]
trainees <- all[!all %in% c(sales$sale, "")]

sales_group[, pos := seq(.N)]

sales1 <- merge(sales, sales_group, by.x = "sale", by.y = "sales1")
sales2 <- merge(sales, sales_group, by.x = "sale", by.y = "sales2")
sales3 <- merge(sales, sales_group, by.x = "sale", by.y = "sales3")
setnames(sales1, c("sale", "plusone", "plustwo", "sales_pos"))
setnames(sales2, c("sale", "plusone", "plustwo", "sales_pos"))
setnames(sales3, c("sale", "plusone", "plustwo", "sales_pos"))
sales_visit_by_sale <- rbind(sales1, sales2, sales3)
sales_visit_by_sale[, with_trainee := FALSE]
sales_visit_by_sale[(plusone %in% trainees) | (plustwo %in% trainees), with_trainee := TRUE]
sales_visit_by_sale[(order(sale, sales_pos)), .(sale, sales_pos, with_trainee)]
  

Комментарии:

1. Я добавил некоторые текущие данные, если это поможет