首页 > 解决方案 > 在 python 中使用 case_when 与 mutate 等效

问题描述

我刚刚开始使用 python,我正在尝试将我创建的一些 R 函数迁移到 python。我对如何基于正则表达式条件创建变异列感到困惑。

目标

我有一个包含文本的数据框。我想提取文本中引用分数的部分,该分数包含字母 m 后跟数字,例如“m3”或“M5”等。想法是,如果存在正则表达式,则应提取数字到名为 MStage 的列。

由于各种边缘情况,正则表达式有点复杂,因此必须使用 ifelse(或 case_when)类型子句按顺序执行多个正则表达式。

R 代码如下所示:

 dataframe <- dataframe %>%
    mutate(
      MStage = map(
        mytext, ~ case_when(
          grepl("(?<=\\d)\\s*[Mm](?:\\s|=)*\\d+", .x,perl = TRUE) ~ stringr::str_replace(stringr::str_extract(.x, "(?<=\\d)\\s*[Mm](?:\\s|=)*\\d+"), "M", ""),
          grepl("(?=[^\\.]*[Bb]arr)[^\\.]*\\s+\\d{2}\\s*[cm]*\\s*(to |-| and)\\s*\\d{2}\\s*[cm]*\\s*", .x, ignore.case = TRUE, perl = TRUE) ~ as.character(as.numeric(sapply(stringr::str_extract_all(stringr::str_extract(.x, "\\d{2}\\s*[cm]*\\s*(to|-|and)\\s*\\d{2}\\s*[cm]*\\s*"), "\\d{2}"), function(y) abs(diff(as.numeric(y)))))),
          grepl("(?=[^\\.]*cm)(?=[^\\.]*[Bb]arr)(?=[^\\.]*(of |length))[^\\.]*", .x, perl = TRUE) ~ stringr::str_extract(paste0(stringr::str_match(.x, "(?=[^\\.]*cm)(?=[^\\.]*[Bb]arr)(?=[^\\.]*(of |length))[^\\.]*"), collapse = ""), "\\d+"),
          grepl("(\\.|^|\n)(?=[^\\.]*(small|tiny|tongue|finger))(?=[^\\.]*[Bb]arr)[^\\.]*(\\.|\n|$)", .x, perl = TRUE) ~ stringr::str_replace(.x, ".*", "1"),
          TRUE ~ "Insufficient"
        )
      )
    )

我的尝试

我已经开始尝试使用以下代码将其转换为 python:

df = df.assign(col = ['pos' if df['text'].str.contains('(?<=\\d)\\s*[Mm](?:\\s|=)*\\d+') else 'Insuf' ])

虽然我得到的错误是:

问题

 ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

如果正则表达式为真(以及根据 R 代码的其他正则表达式),我希望能够添加提取数字的功能

标签: pythonrpandas

解决方案


你得到这个错误的原因是因为if这里需要一个布尔值,但是你给它提供了整个系列的布尔值。通常,您可以使用 lambda 函数来解决此问题。

import re
pat = '(?<=\\d)\\s*[Mm](?:\\s|=)*\\d+'
df = df.assign(col = lambda x: 'pos' if re.search(pat, x) else 'Insuf')

要提取数字,只需使用不同的re方法(可能re.match()如果您只需要第一次出现)代替,'pos'或将替换if elsere.match()和。fillna()'Insuf'assign()

df = df.assign(col = lambda x: re.match(pat, x)).fillna(value='Insuf')

推荐阅读