Если - то с несколькими символами и условиями - PullRequest
0 голосов
/ 18 марта 2019

Я надеюсь, что кто-то может мне помочь, так как мой нынешний подход с grepl не приводит ни к чему, что работает

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

Данные выглядят следующим образом

category                                 

Candidate Biography                        
Candidate Biography                         
Candidate Biography                         
Candidate Biography, Campaign Finance       
Justice, Candidate Biography, Economy       
Candidate Biography, Jobs                   
Economy, Education, Candidate Biography    
Economy, Civil Rights, Candidate Biography

Теперь я хочу создать новые переменные, которые могут принимать различные значения в соответствии с категорией, как показано ниже

category                                 CandBio   Economy  CivilRights   Family
Candidate Biography                         1         0          0           0
Candidate Biography                         1         0          0           0
Candidate Biography                         1         0          0           0
Candidate Biography, Campaign Finance       0.5       0.5        0           0
Justice, Candidate Biography, Economy       0.33      0.33       0.33        0
Candidate Biography, Jobs                   0.5       0.5        0           0
Economy, Education, Candidate Biography     0.33      0.33       0           0.33
Economy, Civil Rights, Candidate Biography  0.33      0.33       0.33        0

Каждая категория имеет определенный коэффициент для каждой переменной (и может загружаться в разные категории). Например. «Биография кандидата, финансирование кампании» загружается на CandBio и Экономику по 0,5 каждый. Категории повторно встречаются для многих наблюдений в наборе данных. (в общей сложности 49 тыс. объектов со 120 различными категориями, которые должны быть объединены в 10 переменных, например, CandBio, Economy, CivilRights и т. д.)

Сначала я попробовал объединить ifelse и grepl, но понял, что grepl очень чувствителен к порядку и что я могу получить классификацию ошибок для каждой категории в зависимости от того, как я структурирую свой ifelse. Также я попытался получить vactors со всеми категориями, которые имеют одинаковое число, и затем включить вектор в функцию grepl, но это тоже не сработало.

Так что я ищу любое решение, которое поможет мне присвоить свои веса переменной в зависимости от текста категории.

Я надеюсь, что смогу четко описать свою проблему, и я с нетерпением жду любой помощи, которая очень ценится! Заранее большое спасибо!

РЕДАКТИРОВАТЬ: Пока я пробовал это таким образом, но безуспешно:

clintontvad$CandidateBiography <- ifelse(ifelse(grepl("Candidate Biography", clintontvad$subjects),1,
                                                ifelse(grepl("Candidate Biography, Marriage, Gays and Lesbians, Civil Rights, Immigration, Trade, Energy, Workers", clintontvad$subjects), 0.125, 
                                                ifelse(grepl("Candidate Biography, Terrorism, Islam, Foreign Policy, Nuclear, Iran", clintontvad$subjects),0.17,
                                                ifelse(grepl("Children, Candidate Biography, Families, Education, Debt, Economy, Jobs", clintontvad$subjects),0.17,
                                                       ifelse(grepl("Candidate Biography, Children, Education, Health Care, Women", clintontvad$subjects), 0.2,
                                                              ifelse(grepl("Candidate Biography, Civil Rights, Islam, Gays and Lesbians, Women", clintontvad$subjects), 0.2,
                                                                     ifelse(grepl("Candidate Biography, Economy, Election, Children, Families", clintontvad$subjects), 0.2,
                                                                            ifelse(grepl("Children, Education, Women, Economy, Families", clintontvad$subjects), 0.2,
                                                                                   ifelse(grepl("Job Accomplishments, Abortion, Women, Health Care, Climate Change, Marriage", clintontvad$subjects), 0.2,
                                                                                          ifelse(grepl("Women, Civil Rights, Gays and Lesbians, Foreign Policy, Canddate Biography", clintontvad$subjects), 0.25, 
                                                                                                 ifelse(grepl("Poverty, Health Care, Candidate Biography, Terrorism", clintontvad$subjects), 0.25,
                                                                                                        ifelse(grepl("Job Accomplishments, Foreign Policy, Health Care, Children", clintontvad$subjects), 0.25,
                                                                                                               ifelse(grepl("Foreign Policy, Terrorism, Candidate Biography", clintontvad$subjects),0.25,
                                                                                                                      ifelse(grepl("Ethics, Terrorism, Candidate Biography", clintontvad$subjects),0.25, 0)))))))))))))

Ответы [ 2 ]

1 голос
/ 18 марта 2019

Если я правильно понял ваш пример, то веса для новых переменных зависят от количества категорий в каждой строке. В этом случае вы можете использовать двухэтапный подход. Сначала создайте свои новые переменные, а затем разделите на количество подходящих категорий.

d <- data.frame(category = c("Candidate Biography", "Candidate Biography", "Candidate Biography", 
                             "Candidate Biography, Campaign Finance", 
                             "Justice, Candidate Biography, Economy", "Candidate Biography, Jobs", 
                             "Economy, Education, Candidate Biography", 
                             "Economy, Civil Rights, Candidate Biography"))

# create a list with all your new variables and their respective categories
categories <- list(
  CandBio = c("Candidate Biography"),   
  Economy = c("Campaign Finance", "Economy", "Jobs"), 
  CivilRights = c("Justice", "Civil Rights"), 
  Family = c("Education")
  )

# create the new variables
for (i in seq_along(categories)) {
  d[names(categories)[i]] <- grepl(paste0(categories[[i]], collapse = "|"), d[, "category"])
}

# divide by number of matched categories
d[, -1] <- d[, -1]/rowSums(d[, -1])

d
                                    category   CandBio   Economy CivilRights    Family
1                        Candidate Biography 1.0000000 0.0000000   0.0000000 0.0000000
2                        Candidate Biography 1.0000000 0.0000000   0.0000000 0.0000000
3                        Candidate Biography 1.0000000 0.0000000   0.0000000 0.0000000
4      Candidate Biography, Campaign Finance 0.5000000 0.5000000   0.0000000 0.0000000
5      Justice, Candidate Biography, Economy 0.3333333 0.3333333   0.3333333 0.0000000
6                  Candidate Biography, Jobs 0.5000000 0.5000000   0.0000000 0.0000000
7    Economy, Education, Candidate Biography 0.3333333 0.3333333   0.0000000 0.3333333
8 Economy, Civil Rights, Candidate Biography 0.3333333 0.3333333   0.3333333 0.0000000
0 голосов
/ 18 марта 2019

Пока я правильно понял, вот один из способов сделать это. Вам нужен вектор совпадений для вашей категории, и вы захотите следить за делом или если у вас есть какие-либо специальные символы. Но это должно начать. Дайте мне знать, если у вас есть какие-либо проблемы с этим. Кроме того, задним числом я назвал слишком много вещей "категория", но вы должны понять. category1 2 и 3 относятся к тому, что входит в ваши более широкие группы (например, Economy и CivilRights). Наконец, если это медленно, вероятно, будет намного быстрее использовать функцию из stringi вместо grepl. Я могу опубликовать изменения, если это базовое решение слишком медленное.

# Example dataframe
df <- data.frame(category = c("cat 1a",
                        "cat 1a",
                        "cat 1a",
                        "cat 1a, cat 2a",
                        "cat 3a, cat 1a, cat 2b",
                        "cat 1a, cat 2c"),
                 stringsAsFactors = F)

# Create a list with strings split based on the comma
string_list <- strsplit(df$category, split = ",", fixed = TRUE)

# Pre defined categories
category1 <- c("cat 1a", "cat 1b", "cat 1c")
category2 <- c("cat 2a", "cat 2b", "cat 2c")
category3 <- c("cat 3a", "cat 3b", "cat 3c")

# Create new columns based on your categories
df$Category_1 <- sapply(1:length(string_list) , function (x) any(grepl(paste(category1, collapse = "|"), unlist(string_list[x]))) / 
                          length(unlist(string_list[x])))
df$Category_2 <- sapply(1:length(string_list) , function (x) any(grepl(paste(category2, collapse = "|"), unlist(string_list[x]))) / 
                          length(unlist(string_list[x])))
df$Category_3 <- sapply(1:length(string_list) , function (x) any(grepl(paste(category3, collapse = "|"), unlist(string_list[x]))) / 
                          length(unlist(string_list[x])))

df
                category Category_1 Category_2 Category_3
1                 cat 1a  1.0000000  0.0000000  0.0000000
2                 cat 1a  1.0000000  0.0000000  0.0000000
3                 cat 1a  1.0000000  0.0000000  0.0000000
4         cat 1a, cat 2a  0.5000000  0.5000000  0.0000000
5 cat 3a, cat 1a, cat 2b  0.3333333  0.3333333  0.3333333
6         cat 1a, cat 2c  0.5000000  0.5000000  0.0000000

РЕДАКТИРОВАТЬ: используя данные, которые @ Gilean0709 любезно предоставил (и stringi, чтобы сделать это быстрее), вот это обновление:

# Example dataframe
df <- data.frame(category = c("Candidate Biography", "Candidate Biography", "Candidate Biography", 
                             "Candidate Biography, Campaign Finance", 
                             "Justice, Candidate Biography, Economy", "Candidate Biography, Jobs", 
                             "Economy, Education, Candidate Biography", 
                             "Economy, Civil Rights, Candidate Biography"), stringsAsFactors = F)


# Create a list with strings split based on the comma
string_list <- strsplit(df$category, split = ",", fixed = TRUE)

library(stringi)

# Pre defined categories
CandBio <- paste(c("Candidate Biography"), collapse = "|")
Economy <- paste(c("Campaign Finance", "Economy", "Jobs"), collapse = "|")
CivilRights <- paste(c("Justice", "Civil Rights"), collapse = "|")
Family <- paste(c("Education"), collapse = "|")

# Create new columns based on your categories
df$CandBio <- sapply(1:length(string_list), function (x) any(stri_detect_regex(unlist(string_list[x]), CandBio)) / 
                          length(unlist(string_list[x])))
df$Economy <- sapply(1:length(string_list), function (x) any(stri_detect_regex(unlist(string_list[x]), Economy)) / 
                          length(unlist(string_list[x])))
df$CivilRights <- sapply(1:length(string_list), function (x) any(stri_detect_regex(unlist(string_list[x]), CivilRights)) / 
                          length(unlist(string_list[x])))
df$Family <- sapply(1:length(string_list), function (x) any(stri_detect_regex(unlist(string_list[x]), Family)) / 
                          length(unlist(string_list[x])))

df %>%
  mutate_if(is.numeric, round, digits = 2)
                                    category CandBio Economy CivilRights Family
1                        Candidate Biography    1.00    0.00        0.00   0.00
2                        Candidate Biography    1.00    0.00        0.00   0.00
3                        Candidate Biography    1.00    0.00        0.00   0.00
4      Candidate Biography, Campaign Finance    0.50    0.50        0.00   0.00
5      Justice, Candidate Biography, Economy    0.33    0.33        0.33   0.00
6                  Candidate Biography, Jobs    0.50    0.50        0.00   0.00
7    Economy, Education, Candidate Biography    0.33    0.33        0.00   0.33
8 Economy, Civil Rights, Candidate Biography    0.33    0.33        0.33   0.00
...