Как запустить функцию (много раз), которая изменяет переменную (tibble) в глобальной среде - PullRequest
2 голосов
/ 01 апреля 2020

Я новичок ie в R, поэтому, пожалуйста, наберитесь терпения и ... советы приветствуются.

Моя цель - создать тиббл, который содержит "Полное имя" ( лицо, которое может иметь от 2 до 4 имен) и его / ее пол. Я должен начать с тиббла, содержащего типичные мужские и женские имена.

Ниже я привожу минимальный рабочий пример.

Моя проблема: я могу звонить get_name() несколько раз (в 10 000 для л oop !!) и получите правильный ответ. Но я искал более «элегантный» способ сделать это. replicate() к сожалению возвращает вектор ... что делает его непригодным для использования.

Мои сомнения: я знаю, что у меня есть некоторые (очень немногие ... правильные !!) проблемы, такие как оператор if, который оценивается каждый раз (который является избыточным), но я не нахожу другой способ сделать это. Любое предложение?

Любые другие предложения о структуре кода также приветствуются.

Большое спасибо заранее за вашу помощь.

# Dummy name list
unit_names <- tribble(
  ~Women, ~Man,
  "fem1", "male1",
  "fem2", "male2", 
  "fem3", "male3",
  "fem4", "male4",
  "fem5", "male5",
  "fem6", NA,
  "fem7", NA
)

set.seed(12345) # seed for test

# Create a tibble with the full names
full_name <- tibble("Full Name" = character(), "Gender" = character() )

get_name <- function() {
  # Get the Number of 'Unit-names' to compose a 'Full-name'
  nbr_names <- sample(2:4, 1, replace = TRUE)
  # Randomize the Gender
  gender  <- sample(c("Women", "Man"), 1, replace = TRUE)
  if (gender == "Women") {
    lim_names <- sum( !is.na(unit_names$"Women"))
  } else {
    lim_names <- sum( !is.na(unit_names$"Man"))
  }

  # Sample the Fem/Man List names (may have duplicate)
  sample(unlist(unit_names[1:lim_names, gender]), nbr_names, replace = TRUE) %>%
    # Form a Full-name
    paste ( . , collapse = " ") %>%
    # Add it to the tibble (INCLUDE the Gender)
    add_row(full_name, "Full Name" = . , "Gender" = gender)
}

# How can I make 10k of this?
full_name <- get_name()

Ответы [ 3 ]

1 голос
/ 01 апреля 2020

Если вы передадите большее число, чем 1, к sample, эту проблему легче будет векторизовать.

Одна вещь, которая в настоящее время делает вашу проблему намного сложнее, - это расположение таблицы unit_names: вы эффективно рассматривают мужские и женские имена как индивидуально спаренные, но они явно не совпадают: следовательно, они не должны быть в столбцах одной и той же таблицы. Используйте список из двух векторов, например:

unit_names = list(
    Women = c("fem1", "fem2", "fem3", "fem4", "fem5", "fem6", "fem7"),
    Men = c("male1", "male2", "male3", "male4", "male5")
)

Затем вы можете сгенерировать случайные имена для удовольствия вашего сердца:

generate_names = function (n, unit_names) {
    name_length = sample(2 : 4, n, replace = TRUE)
    genders = sample(c('Women', 'Men'), n, replace = TRUE)
    names = Map(sample, unit_names[genders], name_length, replace = TRUE) %>%
        lapply(paste, collapse = ' ') %>%
        unlist()
    tibble(`Full name` = names, Gender = genders)
}

Примечание о стиле, в отличие от вашей функции, приведенной выше не используйте глобальные переменные. Кроме того, не заключайте в кавычки имена переменных (вы делаете это в unit_names$"Women" и для аргументов add_row). R допускает это, но это, возможно, ошибка в спецификации языка: это , а не строки , это имена переменных, из-за чего они выглядят как строки, вводящие в заблуждение. В конце концов, вы не цитируете имена других переменных. Вам do необходимо заключить в кавычки имя столбца `Full name`, поскольку оно содержит пробел. Однако использование обратных кавычек вместо кавычек означает, что это имя переменной.

0 голосов
/ 01 апреля 2020

С небольшой помощью от Конрада Рудольфа, следующее элегантное (и векторизованное ... и быстрое) решение, которое я искал. map2 делает необходимый трюк.

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

Еще раз спасибо Конраду.

# Dummy name list
unit_names <- tribble(
  ~Women, ~Men,
  "fem1", "male1",
  "fem2", "male2", 
  "fem3", "male3",
  "fem4", "male4",
  "fem5", "male5",
  "fem6", NA,
  "fem7", NA
)
name_list <- list(
  Women = unit_names$Women[!is.na(unit_names$Women)],
  Men = unit_names$Men[!is.na(unit_names$Men)]
)

generate_names = function (n, name_list) {
  name_length = sample(2 : 4, n, replace = TRUE)
  genders = sample(c('Women', 'Men'), n, replace = TRUE)
  #names = lapply(name_list[genders], sample,  name_length) %>%
  names = map2(name_list[genders], name_length, sample) %>%
    lapply(paste, collapse = ' ') %>%
    unlist()
  tibble(`Full name` = names, Gender = genders)
}

full_name <- generate_names(10000, name_list)
0 голосов
/ 01 апреля 2020

Я не на 100% из того, что вы пытаетесь получить, но если я правильно понял ... вы пробовали использовать mutate в dplyr? Например: result= mutate(data.frame, concated_column = paste(column1, column2, column3, column4, sep = '_'))

...