为在实际数据中增加复杂性而编辑的,请参阅下面。同时,我也接受了一个基于我最初是如何问这个问题的答案。,我试着看了其他几个可用的Q/A,但我看的那些似乎都不适合我,/或者没有足够的细节让我理解如何实现这些解决方案。我不太习惯使用regex,所以我很难想出一个模式。我有多个文本字符串,其中一些可以在数据中组合,这些组合的字符串可以按任意顺序放置。这是一个很长的数据集,对于在数据框架内创建的多个列,我必须重复一个类似的过程,其内容部分基于str_detect函数的真/假,因此效率是相当重要的。
同样重要的是,正如我在其他答案中提到的那样,我对Python/Perl一无所知。我在RStudio工作。
首先,一个与我的数据类似且更简单的数据框架。
SN <- c(1001, 1002, 1003, 1004)
fwd_fender <- c(1, 0, 1, 1)
note <- c("FWD FNDR DMG",
"MID BODY CHASS DMG",
"FWD FNDR EXCESS WEAR, MID BODY CHASS DMG",
"MID BODY CHASS DMG, FWD FNDR PAINT SCRATCH")
df <- data.frame(SN, fwd_fender, note)产生了这一数据框架:
SN fwd_fender note
1 1001 1 FWD FNDR DMG
2 1002 0 MID BODY CHASS DMG
3 1003 1 FWD FNDR EXCESS WEAR, MID BODY CHASS DMG
4 1004 1 MID BODY CHASS DMG, FWD FNDR PAINT SCRATCH基本上,我需要做的是创建另一列,我们称之为fwd_fender_mech_dmg,在那里我可以根据note列重新编码观察结果。在本例中,"FWD FNDR DMG“和"FWD FNDR超额磨损”都算作"fwd_fender_mechanical_dmg“。其他的音符没有。因此,我希望最终生成如下所示的数据框架:
SN fwd_fender note fwd_fender_mech_dmg
1 1001 1 FWD FNDR DMG 1
2 1002 0 MID BODY CHASS DMG 0
3 1003 1 FWD FNDR EXCESS WEAR, MID BODY CHASS DMG 1
4 1004 1 MID BODY CHASS DMG, FWD FNDR PAINT SCRATCH 0我有很多列,有很多不同的变量,所以我试图尽可能多地使用regex (理想情况下),以提高编码的效率,但我没有让它很好地工作。
这是一个基本的测试序列和模式。
yes <- c("FWD FNDR DMG", "FWD FENDER EXCESS WEAR")
no <- c("MID BODY CHASS DMG", "FWD FNDR PAINT SCRATCH")
maybe <- c("FWD FNDR EXCESS WEAR, MID BODY CHASS DMG", "MID BODY CHASS DMG, FWD FNDR PAINT SCRATCH")
s <- c(yes, no, maybe)
pattern <- "FE?ND.*(WEAR|DMG)"
str_detect(s,pattern,negate = FALSE)其结果如下:
[1] TRUE TRUE FALSE FALSE TRUE FALSE这是一个预期的结果,但是请注意,如果我切换了maybe中最后两个条目的顺序,代码就会产生不正确的结果。
yes <- c("FWD FNDR DMG", "FWD FENDER EXCESS WEAR")
no <- c("MID BODY CHASS DMG", "FWD FNDR PAINT SCRATCH")
maybe <- c("FWD FNDR EXCESS WEAR, MID BODY CHASS DMG", "FWD FNDR PAINT SCRATCH, MID BODY CHASS DMG") #Last Entry Reversed
s <- c(yes, no, maybe)
pattern <- "FE?ND.*(WEAR|DMG)"
str_detect(s,pattern,negate = FALSE)它产生了这样的结果:
[1] TRUE TRUE FALSE FALSE TRUE TRUE那么,有什么想法可以让我做这件事吗?
谢谢!
编辑
我的真实数据比最初的简化版本更复杂,所以这里有一个数据框架,它更接近于反映我的数据。
SN <- c(1001, 1002, 1003, 1004)
fwd_fender <- c(1, 0, 1, 1)
fwd_fender_note <- c("FWD FNDR DMG",
"MID BODY CHASS DMG",
"FWD FNDR EXCESS WEAR, MID BODY CHASS DMG",
"MID BODY CHASS DMG, FWD FNDR PAINT SCRATCH")
rear_axel <- c(0, 1, 1, 1)
rear_axel_note <- c("#", "CORROSION", "CORR, CRACK", "CRACK, WEAR")
computer <- c(0, 1, 0, 0)
computer_note <- c("PROGRAM BUG", "ELEC FAULT", "#", "#")
mid_body_chass <- c(1, 1, 0, 1)
mid_body_chass_note <- c("MID BODY CHASS DMG", "WEAR", "#", "CORR")
df <- data.frame(SN, fwd_fender, fwd_fender_note, rear_axel, rear_axel_note, computer, computer_note, mid_body_chass, mid_body_chass_note)它产生这个数据框架:
SN fwd_fender fwd_fender_note rear_axel rear_axel_note computer computer_note mid_body_chass
1 1001 1 FWD FNDR DMG 0 # 0 PROGRAM BUG 1
2 1002 0 MID BODY CHASS DMG 1 CORROSION 1 ELEC FAULT 1
3 1003 1 FWD FNDR EXCESS WEAR, MID BODY CHASS DMG 1 CORR, CRACK 0 # 0
4 1004 1 MID BODY CHASS DMG, FWD FNDR PAINT SCRATCH 1 CRACK, WEAR 0 # 1
mid_body_chass_note
1 MID BODY CHASS DMG
2 WEAR
3 #
4 CORR磨损和裂纹都算作“机械损伤”,因此即使它们是单独的观察,在fwd_fender_mech_dmg列中它们也只应被算作1(只识别某一类型观察的存在与否,而不是有多少)。在这个分析中没有特别跟踪一些观察结果,所以“程序错误”应该是0。
因此,我最终想要达到的是一个数据框架,它看起来有点像以下所示:
rear_axel_corrosion <- c(0, 1, 1, 0)
computer_electrical <- c(0, 1, 0, 0)
mid_body_chass_mech_dmg <- c(1, 1, 1, 1)
df2 <- data.frame(SN, fwd_fender_mech_dmg, rear_axel_mech_dmg, rear_axel_corrosion, computer_electrical, mid_body_chass_mech_dmg)
df2
SN fwd_fender_mech_dmg rear_axel_mech_dmg rear_axel_corrosion computer_electrical mid_body_chass_mech_dmg
1 1001 1 0 0 0 1
2 1002 0 0 1 1 1
3 1003 1 1 1 0 1
4 1004 0 1 0 0 1还要注意的是,有时操作者输入错误的插槽(因此,在"fwd_fender_note“下的”中体小妞DMG“,这意味着实际上应该有一个1在该行的中体底盘损坏。
哇,我知道那是很多,希望我没有把它弄得太复杂。谢谢!
发布于 2021-09-23 00:47:18
代码的问题是,您将'xxx,yyy‘作为两个字符元素(就像字符向量中的那样),但实际上它是一个两个单词的字符标量。
如果我们希望当前正则表达式能够工作,我们可以首先通过逗号对字符串进行str_split,然后对所有子字符串调用str_detect,最后,将输出转换为每行一个逻辑。
library(stringr)
library(purrr)
library(dplyr)
df %>% mutate(fwd_fender_mech_dmg= str_split(note, ',') %>%
map(~str_detect(.x, "FE?ND.*(WEAR|DMG)")%>%
reduce(`|`)))
SN fwd_fender note fwd_fender_mech_dmg
1 1001 1 FWD FNDR DMG 1
2 1002 0 MID BODY CHASS DMG 0
3 1003 1 FWD FNDR EXCESS WEAR, MID BODY CHASS DMG 1
4 1004 1 MID BODY CHASS DMG, FWD FNDR PAINT SCRATCH 0这与昏迷分隔子串的任何顺序都是一致的:
df2<-df%>%mutate(note=replace(note, 4, maybe[2]))
df2 %>% mutate(fwd_fender_mech_dmg = as.integer(str_split(note, ',') %>%
map(~str_detect(.x, "FE?ND.*(WEAR|DMG)")%>%
reduce(`|`))))
SN fwd_fender note fwd_fender_mech_dmg
1 1001 1 FWD FNDR DMG 1
2 1002 0 MID BODY CHASS DMG 0
3 1003 1 FWD FNDR EXCESS WEAR, MID BODY CHASS DMG 1
4 1004 1 FWD FNDR PAINT SCRATCH, MID BODY CHASS DMG 0一些建议
你的数据似乎不“整洁”。“注意”变量偶尔会将两个数据值折叠为单个char元素。
如果将数据分开,那么在下游分析中,可能会使您的生活变得更容易,这样每个值都会有一个观察结果。
为此,您可能需要这样做:
library(dpplyr)
library(stringr)
library(tidyr)
df %>% tidyr::separate_rows(note, sep='\\s*,\\s*') %>% #this separates the rows
mutate(fwd_fender_mech_dmg = +str_detect(note, "FE?ND.*(WEAR|DMG)"))
# A tibble: 6 x 4
SN fwd_fender note fwd_fender_mech_dmg
<dbl> <dbl> <chr> <int>
1 1001 1 FWD FNDR DMG 1
2 1002 0 MID BODY CHASS DMG 0
3 1003 1 FWD FNDR EXCESS WEAR 1
4 1003 1 MID BODY CHASS DMG 0
5 1004 1 MID BODY CHASS DMG 0
6 1004 1 FWD FNDR PAINT SCRATCH 0发布于 2021-09-22 23:50:05
我建议使用tidyverse中的case_when函数:
df %>%
mutate(fwd_fender_mech_dmg = case_when(grepl("FWD FNDR DMG", note) ~ 1,
grepl("FWD FNDR EXCESS WEAR", note) ~ 1,
TRUE ~ 0))输出:
SN fwd_fender note fwd_fender_mech_dmg
1 1001 1 FWD FNDR DMG 1
2 1002 0 MID BODY CHASS DMG 0
3 1003 1 FWD FNDR EXCESS WEAR, MID BODY CHASS DMG 1
4 1004 1 MID BODY CHASS DMG, FWD FNDR PAINT SCRATCH 0https://stackoverflow.com/questions/69292016
复制相似问题