Как добавить добавочный ранг на основе значения столбца? - PullRequest
0 голосов
/ 29 мая 2018

У меня есть фрейм данных в следующем формате:

sample_df <- structure(list(conversationid = c("C1",  "C2", "C2",  "C2", 
"C2",  "C2", "C3",  "C3", "C3",  "C3"), 
sentby = c("Consumer","Consumer", "Agent", "Agent", "Agent", "Consumer", 
"Agent", "Consumer","Agent", "Agent"), 
time = c("2018-04-25 03:54:04.550+0000", "2018-05-11 19:18:05.094+0000", 
     "2018-05-11 19:18:09.218+0000", "2018-05-11 19:18:09.467+0000", 
     "2018-05-11 19:18:13.527+0000", "2018-05-14 22:57:10.004+0000", 
     "2018-05-14 22:57:14.330+0000", "2018-05-14 22:57:20.795+0000", 
     "2018-05-14 22:57:22.168+0000", "2018-05-14 22:57:24.203+0000"),
diff = c(NA, NA, 0.0687333333333333, 0.00415, 0.0676666666666667, NA, 0.0721, 
0.10775, 0.0228833333333333,0.0339166666666667)), 
.Names = c("conversationid", "sentby","time","diff"), row.names = c(NA, 10L), 
class = "data.frame")

Где Параметр разговор - это идентификатор разговора, который может содержать сообщения, отправленные агентом или клиентом.Что я хотел бы сделать, так это поддерживать счетчик выполнения, когда в разговоре появляется «Агент», например:

Целевой результат:

conversationid  sentby  diff    agent_counter_flag
        C1     Consumer NA          0
        C2     Consumer NA          0
        C2     Agent    0.06873333  1
        C2     Agent    0.00415     2
        C2     Agent    0.06766667  3
        C2     Consumer NA          0
        C3     Agent    0.0721      1
        C3     Consumer 0.10775     0
        C3     Agent    0.02288333  2
        C3     Agent    0.03391667  3

В настоящее время я могу разбитьфрейм данных и ранжируйте все записи, сгруппированные по cid, используя следующий код:

setDT(sample_df)
sample_df[,Order := rank(time, ties.method = "first"), by = "conversationid"]
sample_df <- as.data.frame(sample_df)

Но все, что он делает, это ранжирует записи в пределах раздела независимо от того, является ли он «Агентом» или «Клиентом».

Токовый выход:

   conversationid   sentby  diff    Order
        C1     Consumer NA          1
        C2     Consumer NA          1
        C2     Agent    0.06873333  2
        C2     Agent    0.00415     3
        C2     Agent    0.06766667  4
        C2     Consumer NA          5
        C3     Agent    0.0721      1
        C3     Consumer 0.10775     2
        C3     Agent    0.02288333  3
        C3     Agent    0.03391667  4

Как мне поступить, чтобы у меня был мой кадр данных, как показано в целевом выводе?Спасибо!

Ответы [ 4 ]

0 голосов
/ 25 января 2019

Наткнулся на этот пост, пытаясь решить аналогичную проблему с dplyr.Вы можете суммировать логические значения, в которых вы проверяли sentby == "Agent", используя группировку dplyr.

Долгий путь, просто чтобы объяснить, как будет выглядеть логический столбец:

library(dplyr)

sample_df %>%
  mutate(is_agent = sentby == "Agent") %>%
  group_by(conversationid) %>%
  mutate(agent_counter_flag = ifelse(is_agent, cumsum(is_agent), 0)) %>%
  ungroup()
#> # A tibble: 10 x 6
#>    conversationid sentby  time               diff is_agent agent_counter_f…
#>    <chr>          <chr>   <chr>             <dbl> <lgl>               <dbl>
#>  1 C1             Consum… 2018-04-25 03… NA       FALSE                   0
#>  2 C2             Consum… 2018-05-11 19… NA       FALSE                   0
#>  3 C2             Agent   2018-05-11 19…  0.0687  TRUE                    1
#>  4 C2             Agent   2018-05-11 19…  0.00415 TRUE                    2
#>  5 C2             Agent   2018-05-11 19…  0.0677  TRUE                    3
#>  6 C2             Consum… 2018-05-14 22… NA       FALSE                   0
#>  7 C3             Agent   2018-05-14 22…  0.0721  TRUE                    1
#>  8 C3             Consum… 2018-05-14 22…  0.108   FALSE                   0
#>  9 C3             Agent   2018-05-14 22…  0.0229  TRUE                    2
#> 10 C3             Agent   2018-05-14 22…  0.0339  TRUE                    3

Возможно, вы захотите добавить к этому select(-is_agent), чтобы убрать логический столбец.

Или на практике для сокращенной формы вы можете вызвать cumsum внутри mutate.

sample_df %>%
  group_by(conversationid) %>%
  mutate(agent_counter_flag = ifelse(sentby == "Agent", cumsum(sentby == "Agent"), 0)) %>%
  ungroup()

В любом случае, идея заключается в том, что в каждом conversationid вы добавляете число sentby == "Agent", если оно отправлено агентом, или просто устанавливаете в 0, если оно не отправлено агентом.

0 голосов
/ 30 мая 2018
library(data.table)
setDT(sample_df)

sample_df[, agent_counter_flag := {sba = (sentby == 'Agent'); sba*cumsum(sba)}
          , by = conversationid]
sample_df

#     conversationid   sentby                         time       diff agent_counter_flag
#  1:             C1 Consumer 2018-04-25 03:54:04.550+0000         NA                  0
#  2:             C2 Consumer 2018-05-11 19:18:05.094+0000         NA                  0
#  3:             C2    Agent 2018-05-11 19:18:09.218+0000 0.06873333                  1
#  4:             C2    Agent 2018-05-11 19:18:09.467+0000 0.00415000                  2
#  5:             C2    Agent 2018-05-11 19:18:13.527+0000 0.06766667                  3
#  6:             C2 Consumer 2018-05-14 22:57:10.004+0000         NA                  0
#  7:             C3    Agent 2018-05-14 22:57:14.330+0000 0.07210000                  1
#  8:             C3 Consumer 2018-05-14 22:57:20.795+0000 0.10775000                  0
#  9:             C3    Agent 2018-05-14 22:57:22.168+0000 0.02288333                  2
# 10:             C3    Agent 2018-05-14 22:57:24.203+0000 0.03391667                  3

Как указывает @Frank, это также работает

sample_df[, agent_counter_flag := rowid(conversationid, sentby)*(sentby == "Agent")]

Benchmark

sample_df <- replicate(1000, sample_df, simplify = F) %>% rbindlist
microbenchmark(
  rowidFrank = sample_df[, agent_counter_flag := 
                           rowid(conversationid, sentby)*(sentby == "Agent")]
, rowidUwe = sample_df[sentby == "Agent", agent_counter_flag := rowid(conversationid)]
, cumsum   = sample_df[, agent_counter_flag := {sba = (sentby == 'Agent'); sba*cumsum(sba)}
                       , by = conversationid]
, unit = 'relative')

# Unit: relative
# expr            min       lq     mean   median       uq       max neval
# rowidFrank 1.000000 1.000000 1.000000 1.000000 1.000000 1.0000000   100
# rowidUwe   1.448858 1.438742 1.410849 1.414428 1.535292 0.5549433   100
# cumsum     1.322493 1.306228 1.316188 1.261325 1.308371 1.6431036   100
0 голосов
/ 30 мая 2018

Это мое решение data.table, которое использует функцию rowid() и создает новый столбец agent_counter_flag по ссылке:

library(data.table)
setDT(sample_df)
sample_df[sentby == "Agent", agent_counter_flag := rowid(conversationid)][]
    conversationid   sentby                         time       diff agent_counter_flag
 1:             C1 Consumer 2018-04-25 03:54:04.550+0000         NA                 NA
 2:             C2 Consumer 2018-05-11 19:18:05.094+0000         NA                 NA
 3:             C2    Agent 2018-05-11 19:18:09.218+0000 0.06873333                  1
 4:             C2    Agent 2018-05-11 19:18:09.467+0000 0.00415000                  2
 5:             C2    Agent 2018-05-11 19:18:13.527+0000 0.06766667                  3
 6:             C2 Consumer 2018-05-14 22:57:10.004+0000         NA                 NA
 7:             C3    Agent 2018-05-14 22:57:14.330+0000 0.07210000                  1
 8:             C3 Consumer 2018-05-14 22:57:20.795+0000 0.10775000                 NA
 9:             C3    Agent 2018-05-14 22:57:22.168+0000 0.02288333                  2
10:             C3    Agent 2018-05-14 22:57:24.203+0000 0.03391667                  3
0 голосов
/ 29 мая 2018

Вот вы:

library(dplyr)

df <- data.frame(cid = c(rep("c1", 6), rep("C2", 4)),
                 Sent_by = c("Consumer", "Agent", "Consumer", "Consumer", "Agent", "Agent",
                             "Consumer", "Agent", "Agent", "Consumer"))
df %>% group_by(cid, Sent_by) %>%
  mutate(agent_flag = ifelse(Sent_by == "Agent", 1:n(), NA),
         consumer_flag = ifelse(Sent_by == "Consumer", 1:n(), NA))
...