使用 tidyverse,如何用字符模式替换 NA,但如果找不到匹配项则删除整行?

问题描述 投票:0回答:2

你好,我有一个示例数据集如下。

# Load the tidyverse package
library(tidyverse)

# Create the dataset
id <- 1:6
model <- c("0RB3211", NA, "0RB4191",
           NA, "0RB4033", NA)
UPC <- c("805289119081", "DK_0RB3447CP_RBCP  50", "8053672006360",
         "Green_Classic_G-15_Polar_1.67_PREM_SV", "805289044604",
         "DK_0RB2132CP_RBCP  55")
df <- tibble(id, model, UPC)

对于'model'列中的缺失值,如果其对应的UPC以DK开头,我需要提取7位数字和第一个下划线后的字母,然后将其放入'model'列中。例如,对于第二行,我需要将“0RB3447”放入“型号”列,对于第四行,我需要删除整行,对于最后一行,我需要将“0RB2132”放入'模特专栏。

这是我的预期结果:

# Manipulate the dataset
df_cleaned <- df %>%
  rowwise() %>%
  mutate(model = ifelse(is.na(model) & str_detect(UPC, "^DK"),
                        str_extract(UPC, "\\d{2}RB\\d{4}"),
                        model)) %>%
  ungroup() %>%
  filter(!(is.na(model) & str_detect(UPC, "[^0-9]")))

# Display the cleaned dataset
print(df_cleaned)

然而,它只返回这个错误的结果。

如何修改我以前的代码? 真的很感激。

r dataframe data-manipulation
2个回答
2
投票

而不是

ifelse
,另一种选择是
coalesce
与现有的
model
,这样它只用用
str_replace
提取的UPC的子字符串替换模型中的NA。稍后仅保留模型以 0.

开头的行
library(dplyr)
library(stringr)
 df %>% 
  mutate(model = coalesce(model,
      str_replace(UPC, ".*_(0[^_]+\\d+)[A-Z]+_.*", "\\1"))) %>% 
   filter(str_detect(model, "^0"))

-输出

# A tibble: 5 × 3
     id model   UPC                  
  <int> <chr>   <chr>                
1     1 0RB3211 805289119081         
2     2 0RB3447 DK_0RB3447CP_RBCP  50
3     3 0RB4191 8053672006360        
4     5 0RB4033 805289044604         
5     6 0RB2132 DK_0RB2132CP_RBCP  55

在OP的代码中,不需要

rowwise
,因为
ifelse
是矢量化的。此外,
\\d{2}
不会像
0RB..
那样匹配某些字符串,只显示一个数字而不是 RB 前的 2。因此,用
+
表示一个或多个数字

df %>%
  mutate(model = ifelse(is.na(model) & str_detect(UPC, "^DK"),
                        str_extract(UPC, "(?<=_)\\d+RB\\d{4}"),
                        model)) %>%
  filter(complete.cases(model))

-输出

# A tibble: 5 × 3
     id model   UPC                  
  <int> <chr>   <chr>                
1     1 0RB3211 805289119081         
2     2 0RB3447 DK_0RB3447CP_RBCP  50
3     3 0RB4191 8053672006360        
4     5 0RB4033 805289044604         
5     6 0RB2132 DK_0RB2132CP_RBCP  55

0
投票

我也无法让

str_match
工作,但我确实想出了一个解决方法:

df_cleaned <- df %>% 
  rowwise() %>% 
  mutate(model = case_when(is.na(model) & grepl("DK", UPC) ~ str_split(UPC, "_")[[1]][2], 
                           TRUE ~ model)) %>% 
  ungroup() %>% 
  filter(!(is.na(model) & str_detect(UPC, "[^0-9]")))

grepl
检测“DK”是否在 UPC 中。
str_split
创建一个包含 1 个项目的列表,其中三个字符串由下划线 (_) 分隔。你想要第二个项目,因此
str_split(UPC, "_")[[1]][2]
.

此外,我发现

case_when()
ifelse()
的更清洁替代品。它像

一样工作
case_when([if statement] ~ [then statement],
          TRUE ~ [then statement])

其中 TRUE 本质上意味着“如果以上都不是真的”。

输出:

# A tibble: 5 × 3
     id model     UPC                  
  <int> <chr>     <chr>                
1     1 0RB3211   805289119081         
2     2 0RB3447CP DK_0RB3447CP_RBCP  50
3     3 0RB4191   8053672006360        
4     5 0RB4033   805289044604         
5     6 0RB2132CP DK_0RB2132CP_RBCP  55
© www.soinside.com 2019 - 2024. All rights reserved.