R语言嵌套ifelse语句异常:Transaction_Days分类错误求助
问题:嵌套ifelse分类逻辑异常,多数Transaction_Days被错误归类到"1-7 Days"
问题背景
编写的嵌套ifelse语句仅第一个分支(0-1 Day of Game)正常工作,其余大部分Transaction_Days被错误划分到"1-7 Days"类别。已知:
Status取值为"SOLD"或"AVAILABLE"Transaction_Days是取值≥0的字符型变量
原代码:
pl_df$Event_Time_Category <- ifelse(pl_df$Status=="SOLD", ifelse(pl_df$Transaction_Days<1, '0-1 Day of Game', ifelse(pl_df$Transaction_Days>0 & pl_df$Transaction_Days<8 , '1-7 Days', ifelse(pl_df$Transaction_Days>7 & pl_df$Transaction_Days<32, '7-31 Days', ifelse(pl_df$Transaction_Days>31 & pl_df$Transaction_Days<91, '31-90 Days', '90+ Days Out')))), '')
实际输出(异常):
Transaction_Days Event_Time_Category 72 1-7 Days 3 1-7 Days 10 1-7 Days 37 1-7 Days 61 1-7 Days 35 1-7 Days 126 1-7 Days 92 90+ Days Out 53 1-7 Days 11 1-7 Days 48 1-7 Days 19 1-7 Days 21 1-7 Days 66 1-7 Days 20 1-7 Days 49 1-7 Days 21 1-7 Days 43 1-7 Days 31 1-7 Days 0 0-1 Day of Game
预期输出:
Transaction_Days Event_Time_Category 72 31-90 Days 3 1-7 Days 10 7-31 Days 37 31-90 Days 61 31-90 Days 35 31-90 Days 126 90+ Days Out 92 90+ Days Out 53 31-90 Days 11 7-31 Days 48 31-90 Days 19 7-31 Days 21 7-31 Days 66 31-90 Days 20 7-31 Days 49 31-90 Days 21 7-31 Days 43 31-90 Days 31 7-31 Days 0 0-1 Day of Game
数据框结构:
structure(list(Promoter = c("ABC", "ABC", "ABC", "ABC", "ABC", "ABC"), Event.Date = c("2022-07-27 13:10:00", "2022-07-27 13:10:00", "2022-07-27 13:10:00", "2022-07-27 13:10:00", "2022-07-27 13:10:00", "2022-07-27 13:10:00"), Description = c("Twins @ Brewers", "Twins @ Brewers", "Twins @ Brewers", "Twins @ Brewers", "Twins @ Brewers", "Twins @ Brewers" ), Performer = c("Milwaukee Brewers", "Milwaukee Brewers", "Milwaukee Brewers", "Milwaukee Brewers", "Milwaukee Brewers", "Milwaukee Brewers" ), Category = c("MLB", "MLB", "MLB", "MLB", "MLB", "MLB"), Transaction.Date = c("2022-05-16 17:42:00", "2022-07-24 21:12:00", "2022-07-17 14:16:00", "2022-06-20 13:24:00", "2022-05-27 17:24:00", "2022-06-22 19:25:00"), Zone = c("Field Diamond Box", "Field Diamond Box", "Field Diamond Box", "Field Infield Box", "Field Infield Box", "Field Infield Box"), Section = c(111L, 111L, 111L, 110L, 110L, 110L), Row = c("3", "4", "4", "6", "6", "6"), Seat = c("9, 10", "5, 6", "7, 8", "10, 11, 12", "5, 6, 7", "8, 9"), Quantity = c(2L, 2L, 2L, 3L, 3L, 2L), Status = c("SOLD", "SOLD", "SOLD", "SOLD", "SOLD", "SOLD"), Price = c(85.47, 72.05, 72.86, 45.36, 44.73, 43.75), Cost = c(164, 164, 164, 174, 174, 116), Revenue = c(170.94, 144.1, 145.72, 136.08, 134.19, 87.5 ), Profit = c(6.94, -19.9, -18.28, -37.92, -39.81, -28.5), Event_Date = structure(c(19200, 19200, 19200, 19200, 19200, 19200), class = "Date"), Transaction_Date = structure(c(19128, 19197, 19190, 19163, 19139, 19165), class = "Date"), Alias = c(" Twins @ Brewers", " Twins @ Brewers", " Twins @ Brewers", " Twins @ Brewers", " Twins @ Brewers", " Twins @ Brewers"), Cost_Per_Ticket = c(82, 82, 82, 58, 58, 58), Revenue_Per_Ticket = c("85.47", "72.05", "72.86", "45.36", "44.73", "43.75"), Pack_Size = c("2", "2", "2", "3", "3", "2" ), Transaction_Days = c("72", "3", "10", "37", "61", "35"), Event_Time_Category = c("1-7 Days", "1-7 Days", "1-7 Days", "1-7 Days", "1-7 Days", "1-7 Days"), Event_Time = c("01:10 PM", "01:10 PM", "01:10 PM", "01:10 PM", "01:10 PM", "01:10 PM")), row.names = c(NA, 6L), class = "data.frame")
问题根源
Transaction_Days是字符型变量,直接做数值比较时会按字典序而非数值大小判断。例如字符"10"和"8"比较时,会先看第一个字符'1'和'8','1'的ASCII码小于'8',所以"10" < "8"会返回TRUE,导致所有以'1'开头的天数(如10、11、19等)都被错误判定为小于8,进而归类到"1-7 Days"。
解决方案
方案1:转换为数值型后再执行嵌套ifelse
先将Transaction_Days转换为数值型,再进行比较判断:
# 先转换变量类型 pl_df$Transaction_Days <- as.numeric(pl_df$Transaction_Days) # 执行分类逻辑 pl_df$Event_Time_Category <- ifelse(pl_df$Status=="SOLD", ifelse(pl_df$Transaction_Days < 1, '0-1 Day of Game', ifelse(pl_df$Transaction_Days > 0 & pl_df$Transaction_Days < 8, '1-7 Days', ifelse(pl_df$Transaction_Days >7 & pl_df$Transaction_Days <32, '7-31 Days', ifelse(pl_df$Transaction_Days >31 & pl_df$Transaction_Days <91, '31-90 Days', '90+ Days Out')))), '')
方案2:使用cut()函数简化分类(更推荐)
嵌套ifelse可读性差,用cut()函数可以更简洁地实现区间分类:
# 转换变量类型 pl_df$Transaction_Days <- as.numeric(pl_df$Transaction_Days) # 定义区间和对应标签 breaks <- c(-Inf, 0, 7, 31, 90, Inf) labels <- c('0-1 Day of Game', '1-7 Days', '7-31 Days', '31-90 Days', '90+ Days Out') # 仅对Status为"SOLD"的行分类,其余为空 pl_df$Event_Time_Category <- ifelse(pl_df$Status == "SOLD", cut(pl_df$Transaction_Days, breaks = breaks, labels = labels, right = FALSE), "")
注:
right = FALSE表示区间左闭右开,例如[0,7)对应1-7 Days,符合需求。
修复后输出
执行上述代码后,分类结果将与预期输出一致:
Transaction_Days Event_Time_Category 72 31-90 Days 3 1-7 Days 10 7-31 Days 37 31-90 Days 61 31-90 Days 35 31-90 Days 126 90+ Days Out 92 90+ Days Out 53 31-90 Days 11 7-31 Days 48 31-90 Days 19 7-31 Days 21 7-31 Days 66 31-90 Days 20 7-31 Days 49 31-90 Days 21 7-31 Days 43 31-90 Days 31 7-31 Days 0 0-1 Day of Game
内容的提问来源于stack exchange,提问作者kapsha
相关产品推荐
相关产品推荐

