将NA更改为另一列中字符串的一部分

时间:2019-01-03 08:06:03

标签: r string dataframe

我想提取特定列中的某些字符串并替换NA。 对于下面的data.frame,当电子邮件信息为NA时,我想将字符串提取到另一列中。 字符串始终在“主题”列中的“ developer_id =”和“&app_id”之间。

    |Email      |  Subject                                    |
    |a@site.com |  developer_id=a@site.com&app_id=a&appname=a |
    |NA         |  developer_id=b@site.com&app_id=b&appname=b |
    |c@site.com |  NA                                         |
    |NA         |  developer_id=d@site.com&app_id=d&appname=d |

我期望的结果如下。

    |Email      |  Subject                                    |
    |a@site.com |  developer_id=a@site.com&app_id=a&appname=a |
    |b@site.com |  developer_id=b@site.com&app_id=b&appname=b |
    |c@site.com |  NA                                         |
    |d@site.com |  developer_id=d@site.com&app_id=d&appname=d |

2 个答案:

答案 0 :(得分:0)

使用base R的一个选项是提取第二列的子字符串,该子字符串与第一列中的NA元素相对应,并用提取的值更新第一列NA元素。 / p>

i1 <- is.na(df1$Email) # create a logical index
df1$Email[i1] <- regmatches(df1$Subject[i1], 
                   regexpr("[a-z]+@.*\\.com", df1$Subject[i1]))
df1
#       Email                                    Subject
#1 a@site.com developer_id=a@site.com&app_id=a&appname=a
#2 b@site.com developer_id=b@site.com&app_id=b&appname=b
#3 c@site.com                                       <NA>
#4 d@site.com developer_id=d@site.com&app_id=d&appname=d

或使用tidyverse

library(tidyverse)
df1 %>%
  mutate(Email = case_when(is.na(Email) ~ str_extract(Subject, "[a-z]+@.*\\.com"), 
                  TRUE ~ Email))

此外,正如OP中提到的将单独的字符串用作标识符一样,我们可以对这些字符串使用正则表达式环视,即提取出developer_id=之后且&app_id之前的所有字符

df1 %>%
   mutate(Email = case_when(is.na(Email) ~ 
         str_extract(Subject, "(?<=developer_id\\=).*(?=&app_id)"), 
        TRUE ~ Email))

数据

df1 <- structure(list(Email = c("a@site.com", NA, "c@site.com", NA), 
Subject = c("developer_id=a@site.com&app_id=a&appname=a", 
"developer_id=b@site.com&app_id=b&appname=b", NA, 
  "developer_id=d@site.com&app_id=d&appname=d"
)), class = "data.frame", row.names = c(NA, -4L))

答案 1 :(得分:0)

根据您的请求,

  1. Subject == NA时,Email = Email
  2. Subject != NA时,提取字符串
    • developer_id=之间
    • &app_id

此提取可以通过函数stringr::str_extract(x, pattern)

完成

使用正则表达式pattern = "(?<=developer_id=).*(?=&app_id)"

第一部分(?<=developer_id=)将找到字符后跟 developer_id=.*表示此模式之后的任何字符。之后,(?=&app_id)将匹配后跟&app_id的字符。

换句话说,我们可以在developer_id=&app_id之间找到所需的部分。

使用dplyr::mutateifelse(),您可以轻松地转换给定的列。

library(tidyverse) # dplyr, stringr
mydf %>% # your data
  mutate(Email = ifelse(
    is.na(Subject),
    Email,
    str_extract(Subject, pattern = "(?<=developer_id=).*(?=&app_id)")
  ))
#> # A tibble: 4 x 2
#>   Email      Subject                                   
#>   <chr>      <chr>                                     
#> 1 a@site.com developer_id=a@site.com&app_id=a&appname=a
#> 2 b@site.com developer_id=b@site.com&app_id=b&appname=b
#> 3 c@site.com <NA>                                      
#> 4 d@site.com developer_id=d@site.com&app_id=d&appname=d