【问题标题】:If - Then with multiple characters and conditionsIf - Then 有多个字符和条件
【发布时间】:2019-03-18 13:57:14
【问题描述】:

我希望有人可以帮助我,因为我目前使用 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 和 Economy 上的“候选人传记,竞选财务”各加载 0.5。对于数据集中的许多观察,类别会重新出现。 (在示例中,总共 49k obs 有 120 个不同类别,需要聚合成 10 个变量,例如 CandBio、Economy、CivilRights 等)

我第一次尝试结合 ifelse 和 grepl,但我意识到 grepl 对顺序非常敏感,并且我可以根据我的 ifelse 结构获得每个类别的故障分类。此外,我尝试获取具有相似数字的所有类别术语的向量,然后将向量包含在 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)))))))))))))

【问题讨论】:

  • 我不完全遵循您的逻辑,但我可以建议您不要以这种 CSV 格式存储您的类别,这种格式是非规范化的,因此使用起来很棘手。相反,请考虑将每个类别放在单独的一行。
  • 假设您有类别 A、B、D、F、C(故意无序)。负载总是均匀分布吗?
  • Thx... 基本上我想要的是一个变量为特定的字符串或字符串组合采用特定的值。不同的字符串或字符串组合可以导致相同的值。我想 grepl 不是最好的解决方案,我还能做些什么来使变量为特定字符串取特定值?如果出现“ABD、ACE、YXZ”、“DEF”或“DAB、EDF”,则如果出现“ABD、DAB”或“XYZ”,则 Var1 取 0.33 如果出现“ABD”,则 VAR1 取变量 0.5 VAR1 取值 1还有 0 个。
  • 首先,您应该创建一个表示您想要的映射的数据结构,例如,myvars = list(CandBio = "Candidate Biography", Economy = c("Economy", "Campaign Finance")) 从那里,我认为其他人可以更直接地帮助编码。

标签: r if-statement character grepl


【解决方案1】:

如果我正确理解了您的示例,那么新变量的权重取决于每行中的类别数。在这种情况下,您可以使用两步法。首先创建新变量,然后除以匹配类别的数量。

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

【讨论】:

    【解决方案2】:

    只要我理解正确,这是一种方法。您需要为您的类别提供一个匹配向量,并且您需要密切关注大小写或是否有任何特殊字符。但这应该让你开始。如果您有任何问题,请告诉我。此外,事后看来,我将太多东西命名为“类别”,但您应该明白这一点。 category1 23 指的是构成您更广泛的组的任何内容(例如,EconomyCivilRights)。最后,如果这很慢,那么使用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,以使其更快),这是一个 udpdate:

    # 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
    

    【讨论】:

    • 谢谢!然而,单词的数量不一定与分配给主要类别的数字相关。我对我的主要问题进行了编辑以使其更加清晰......
    • 我看不出您的编辑与两个答案有何不同。两个答案都使用类别的数量而不是单词的数量。你能进一步澄清吗?
    • 嗨安德鲁斯,也许我误解了...让我试试,我会回复你...谢谢!
    • 嗯,实际上,从头开始。看起来另一个解决方案是基于每行的匹配数(所以每行总和为 100%)。如果我错了,请纠正我,@ Gilean0709。我知道我提出的解决方案是基于示例数据框的category 列中的类别数。例如,Candidate Biography 是 1,Candidate Biography, Campaign Finance 是 2。希望这会有所帮助:)
    • 假设我们添加到 CandBio
    猜你喜欢
    • 2019-10-20
    • 1970-01-01
    • 2023-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-05
    • 1970-01-01
    相关资源
    最近更新 更多