假设我有以下数据集:
df <- read.table(header=TRUE, text="name value
stranger_things_mc Stranger_Land
stranger_things_confidence 100
stranger_things_importance 1
stranger_things_answer Stranger_Things
immigrant_crime_number 140
immigrant_crime_confidence 100
immigrant_crime_importance 3
immigrant_crime_answer 50
dog_things_mc Stranger_Land
dog_things_confidence 100
dog_things_importance 1
dog_things_answer Stranger_Things
fighting_stats_number 140
fighting_stats_confidence 100
fighting_stats_answer 50")
每第四行应该都包含三个后缀(_confidence,_importance,_answer),尽管有时不包含(例如上述“ fighting_stats”)。行有时带有(_mc)后缀,而其他时候它会说(_number或_slider)。
我想过滤出包含(_number或_slider)以及与该_number或_slider列关联的三行的任何行。因此,在上面的示例中,结果输出为:
df <- read.table(header=TRUE, text="name value
stranger_things_mc Stranger_Land
stranger_things_confidence 100
stranger_things_importance 1
stranger_things_answer Stranger_Things
dog_things_mc Stranger_Land
dog_things_confidence 100
dog_things_importance 1
dog_things_answer Stranger_Things")
我可以像这样过滤掉特定的列:
final_results <- df %>%
filter(!str_detect(name, "_number") & !str_detect(name, "_slider"))
,但无法弄清楚如何删除所有关联的列。通用算法应为:
首先,在名称列中找到带有“ _number”或“ _slider”的行,并获取其前面的文本。在上面的示例中,将是“ fighting_stats”和“ immigrant_crime”。然后,删除任何包含该文本的行。
答案 0 :(得分:2)
我们基于每四行是一个新块(gl
)的条件创建一个分组列,然后在{name的filter
元素所在的组中first
而不是_number
或_slider
,然后ungroup
并删除创建的临时“ grp”列
library(dplyr)
df %>%
group_by(grp = as.integer(gl(n(), 4, n()))) %>%
filter(!str_detect(first(name), "_(number|slider)")) %>%
ungroup %>%
select(-grp)
基于来自OP的注释,即块由它们的公共前缀确定,然后提取第一个word
,将其用作分组变量并像以前一样进行filter
library(stringr)
df %>%
group_by(grp = word(name, 1, sep="_")) %>%
filter(!str_detect(first(name), "_(number|slider)"))
和ungroup
部分与以前的相同
如果存在重复的前缀(即不相邻的前缀),并且需要将其视为单独的块,请使用rleid
中的data.table
创建分组变量
df %>%
group_by(grp = rleid(word(name, 1, sep="_"))) %>%
filter(!str_detect(first(name), "_(number|slider)"))
答案 1 :(得分:1)
这是我要解决的方法:
groups <- df %>%
mutate(grp = str_extract(name, '.*(?=_confidence|_importance|_answer|_mc|_number|_slider)'),
sfx = str_extract(name, '(_confidence|_importance|_answer|_mc|_number|_slider)')) %>%
group_by(grp) %>%
summarize(confidence = '_confidence' %in% sfx,
importance = '_importance' %in% sfx,
answer = '_answer' %in% sfx,
mc = '_mc' %in% sfx,
number = '_number' %in% sfx,
slider = '_slider' %in% sfx) %>%
ungroup() %>%
gather(sfx, contains, -grp) %>%
filter(contains == TRUE) %>%
select(-contains)
df %>%
mutate(grp = str_extract(name, '.*(?=_confidence|_importance|_answer|_mc|_number|_slider)')) %>%
anti_join(groups %>%
filter(sfx == 'number') %>%
select(grp))
从高层次上讲,我正在创建一个中间数据框,其中包含字符串name
的词干和后缀,并使用词干创建一个组,并确定其中包含哪些后缀集列表每组茎。然后,我们不是在原始数据帧上使用filter
,而是在中间数据帧上使用filter
,然后在原始数据帧上使用anti_join
。
让我们详细介绍一下:
mutate(grp = str_extract(name, '.*(?=_confidence|_importance|_answer|_mc|_number|_slider)'),
sfx = str_extract(name, '(_confidence|_importance|_answer|_mc|_number|_slider)'))
这部分是我们如何使用正则表达式将name
列拆分为其组成部分。
group_by(grp) %>%
summarize(confidence = '_confidence' %in% sfx,
importance = '_importance' %in% sfx,
answer = '_answer' %in% sfx,
mc = '_mc' %in% sfx,
number = '_number' %in% sfx,
slider = '_slider' %in% sfx) %>%
ungroup()
在这里,我们按照我称为grp
的“词根”进行分组,然后查找每个后缀。这部分有点笨拙,如果您的数据中有更多组,则需要扩展。
gather(sfx, contains, -grp) %>%
filter(contains == TRUE) %>%
select(-contains)
在这里,我们将数据转换为“长”样式的数据框,并且仅保留每个组中实际包含的后缀。
这完成了中间数据帧。
df %>%
mutate(grp = str_extract(name, '.*(?=_confidence|_importance|_answer|_mc|_number|_slider)'))
我们首先必须在原始数据帧上创建grp
列,以使anti_join
正常工作。
anti_join(groups %>%
filter(sfx == 'number') %>%
select(grp))
最后,我们将中间数据帧的过滤版本anti_join
转换为原始数据帧。我相信这将达到您想要的效果。
希望有帮助!