以下是两种方法:
第一种仅使用existing_text中的信息进行分组,并根据此分组和keystroke构造within_words列。
第二种方法只使用keystroke中的信息。
第一种方法:基于existing_text的分组和基于keystroke的内容:
我们采取三个步骤:
首先,我们根据strsplit 计算分组,其中我们查找以单词\\w 开头的空格\\s。我们需要更正"SHIFT" 的值,因为它们应该计入"SPACE" 之后的单词中。
第二步是将"SHIFT"(以及示例数据不包含的所有其他类似函数)替换为""。
第三,我们用paste0(..., collapse = "")折叠字符串。
library(tidyverse)
x %>%
# step1: construct grouping:
mutate(word_grp = lengths(strsplit(existing_text, "(?<=\\w)\\s", perl = TRUE)) %>%
if_else(keystroke == "SHIFT", lead(., default = last(.)), .)) %>%
group_by(experiment_id, word_grp) %>%
# step 2 & 3: first replace keys like "SHIFT" with "", the collapse with `paste0`
mutate(within_word = str_replace_all(keystroke, c("SHIFT" = "", "SPACE" = "")) %>%
paste0(., collapse = ""))
#> # A tibble: 24 x 6
#> # Groups: experiment_id, word_grp [6]
#> experiment_id keystroke existing_text final_text word_grp within_word
#> <chr> <chr> <chr> <chr> <int> <chr>
#> 1 1a a "a" a Bad man 1 a
#> 2 1a SPACE "a " a Bad man 1 a
#> 3 1a SHIFT "a " a Bad man 2 beDELETEad
#> 4 1a b "a B" a Bad man 2 beDELETEad
#> 5 1a e "a Be" a Bad man 2 beDELETEad
#> 6 1a DELETE "a B" a Bad man 2 beDELETEad
#> 7 1a a "a Ba" a Bad man 2 beDELETEad
#> 8 1a d "a Bad" a Bad man 2 beDELETEad
#> 9 1a SPACE "a Bad " a Bad man 2 beDELETEad
#> 10 1a m "a Bad m" a Bad man 3 man
#> # … with 14 more rows
第二种方法:仅基于keystrokes 中的信息。
这是一种仅使用keystroke 中信息的方法。但是,如果我们只想使用 keystroke 中的数据,事情会变得更加费力。
以下是对以下步骤的简短说明:
步骤 1a:数据清理
我们需要清理keystrokes 中的数据,以便它们可以用于新列within_word。这意味着两件事:(a) 我们需要用"" 替换每个不应在within_word 中打印的击键。在此之前,我们需要 (b) 根据该键的功能更改前导击键。对于SHIFT,这意味着我们需要设置前导keystroketoupper。对于您的示例数据,这非常简单,因为我们只需要处理SHIFT。但是,在您的真实数据中可能有许多类似的其他键,例如 ALT 或 ^。所以我们需要对每个键重复步骤 1a。理想情况下,我们会想出一个函数,该函数采用键的名称和它在前导 keystroke 上使用的函数。请注意,我们尚未在此步骤中包含 "SPACE",因为我们在第 2 步中需要它。
要查看您需要在实际数据中处理多少键,我们可以过滤那些不更改 existing_text 的 keystrokes。在您的示例数据中,这只是SHIFT:
# get all keystrokes that don't change the existing_text directly
x %>%
select(keystroke, existing_text) %>%
filter(existing_text == lag(existing_text, default = ""))
#> # A tibble: 2 x 2
#> keystroke existing_text
#> <chr> <chr>
#> 1 SHIFT "a "
#> 2 SHIFT "a "
第 2 步:创建分组
我们需要在within_text 中创建单词分组。这是最复杂的一步。下面我们首先查找within_word == "SPACE" 的行以及后续行是!= "SPACE"。我们在结果上使用data.table::rleid 来获取此变量的运行长度ID。最后,我们需要为那些within_word == "SPACE" 的行减去1。
第 3 步:最后一步之前的数据准备
这与步骤 1a 基本相似,我们需要将"SPACE" 替换为"",因为我们不希望它出现在我们的结果中。但是,由于我们在第 2 步中需要此列,因此我们必须在此步骤中完成数据清理。
第 4 步:折叠 within_word 中的字符串
最后,我们按experiment_id 和word_grp 分组,并将within_word 和paste0(..., collapse = "") 中的字符串折叠起来。
library(tidyverse)
# step 1a: data cleaning
mutate(within_word = if_else(lag(keystroke, default = first(keystroke)) == "SHIFT",
toupper(keystroke),
keystroke) %>%
str_replace_all(., c("SHIFT" = ""))) %>%
# step 1b to 1n: repeat step 1a for other keys like ALT, ^ etc.
# step 2: create groups
group_by(experiment_id) %>%
mutate(word_grp = data.table::rleid(
within_word == "SPACE" & lead(within_word, default = first(keystroke)) != "SPACE"
) %>% if_else(within_word == "SPACE", . - 1L, .)) %>%
# step 3: data prep before final step
ungroup %>%
mutate(within_word = str_replace(within_word, "SPACE", "")) %>%
# step 4: collapse
group_by(experiment_id, word_grp) %>%
mutate(within_word = paste0(within_word, collapse = ""))
#> # A tibble: 24 x 6
#> # Groups: experiment_id, word_grp [6]
#> experiment_id keystroke existing_text final_text within_word word_grp
#> <chr> <chr> <chr> <chr> <chr> <int>
#> 1 1a a "a" a Bad man a 1
#> 2 1a SPACE "a " a Bad man a 1
#> 3 1a SHIFT "a " a Bad man BeDELETEad 3
#> 4 1a b "a B" a Bad man BeDELETEad 3
#> 5 1a e "a Be" a Bad man BeDELETEad 3
#> 6 1a DELETE "a B" a Bad man BeDELETEad 3
#> 7 1a a "a Ba" a Bad man BeDELETEad 3
#> 8 1a d "a Bad" a Bad man BeDELETEad 3
#> 9 1a SPACE "a Bad " a Bad man BeDELETEad 3
#> 10 1a m "a Bad m" a Bad man man 5
#> # … with 14 more rows
由reprex package (v0.3.0) 于 2021 年 12 月 23 日创建