【问题标题】:How to select the integer and float values from every rows?如何从每一行中选择整数和浮点值?
【发布时间】:2020-03-30 17:55:18
【问题描述】:

我有一个数据框,每行都包含字符串、浮点数和整数? 我需要从右到左提取所有整数和浮点值,直到出现字母表? 数据框(df1)是

df1:
    text
0   NS-100ML(GLASS) IV 1 19.25
1   India 560 into SI  10  63.26
2   INJ 2 914.20

我需要df1 输出类似

df1:
    text
0   [1,   19.25]
1   [10,  63.26]
2   [2,   914.20]

注意:请不要建议我取最后两个拆分字符串,因为我的下一个数据框 (df2) 看起来不同,如下所示,

df2:
    text
0   NS-100ML(GLASS) IV 1.00 4.95 63.36 96.45
1   India into 456 SI  8.0 52.30 53.46 12.03
2   INJ 2.0 63.80 34.30 56.36

我的df2输出喜欢

df2:
    text
0   [1.0, 4.95,  63.36, 96.45]
1   [8.0, 52.30, 53.46, 12.03]
2   [2.0, 63.80, 34.30, 56.36]

最终,我需要从右到左提取所有浮点数和整数(不同的数据帧可以有不同长度的整数和浮点数)

【问题讨论】:

  • 也许df['text2'] = df['text'].str.findall(r'\d{,3}\.\d{,3}') 假设句点前后不超过三位数。如果要覆盖列,请将“text2”更改为“text”,但新列可能适合测试。
  • 你的第一句话需要更精确(而不是问题:-|),例如(如果我的理解是正确的)“我有一个包含以一个或多个数字开头的行的数据框,后面是空格,后面是一串字符,最后一个不是数字,后面是浮点数和/或整数的字符串表示形式,以空格分隔。"
  • 您仍然需要澄清您的问题(参考我之前的评论),部分原因是您应该感谢许多 SO 成员,他们将来会阅读您的问题。
  • 您在发布答案后在字符串中添加了数字。这从本质上改变了问题,使答案不正确甚至荒谬。你显然不能那样做。我很惊讶这对你来说并不明显。请将您的问题回滚到该编辑之前。如果你愿意,你可以再问一个问题。
  • 我投票决定将此问题作为离题结束,因为在发布了几个答案后,OP 对问题进行了实质性更改,导致答案不正确。 OP 被要求回滚到原来的问题,但没有这样做。

标签: regex python-3.x pandas dataframe


【解决方案1】:

尝试将 apply 与正则表达式结合使用,

df1['text'].apply(lambda x: [i for i in x.split() if not re.match('[A-Za-z\W]', i)])

0     [1, 19.25]
1    [10, 63.26]
2    [2, 914.20]


df2['text'].apply(lambda x: [i for i in x.split() if not re.match('[A-Za-z\W]', i)])


0    [1.00, 4.95, 63.36, 96.45]
1    [8.0, 52.30, 53.46, 12.03]
2    [2.0, 63.80, 34.30, 56.36]

【讨论】:

  • 嗨,感谢您的解决方案,如果我在单词之间有数字怎么办?我不想选他们。请再次检查问题。
【解决方案2】:

您可以将字符串方法 replacesplit 组合用于 pandas 系列。请注意,方括号中的点(.) 表示文字点。

df1['text'].str.extract("( [0-9 .]+)$", expand=False).str.split()

0    [1, 19.25]
1    [10, 63.26]
2    [2, 914.20]


df2['text'].str.extract("( [0-9 .]+)$", expand=False).str.split()

0    [1.00, 4.95, 63.36, 96.45]
1    [8.0, 52.30, 53.46, 12.03]
2    [2.0, 63.80, 34.30, 56.36]

来自 cmets 的其他示例

df = pd.DataFrame({'text':['NEOVEC INJ 385251 APR/2021 5.00 89.00 445.00']})

df['text'].str.extract("( [0-9 .]+)$", expand=False).str.split()

0    [5.00, 89.00, 445.00]

【讨论】:

  • 嗨,感谢您的解决方案,如果我在单词之间有数字怎么办?我不想选他们。请再次检查问题。
  • 如果你在最后一个字母/单词之前(或两个单词之间)有任何数字,它将被取消。在 df2 的第二行中,单词之间有一个数字(India into 456 SI 8.0 52.30 53.46 12.03456 介于 intoSI 之间)并且它已被取消。清楚了吗?
  • 但它无法跟踪数据NEOVEC INJ 385251 APR/2021 5.00 89.00 445.00 这里我只需要5.00 89.00 445.00 根据问题。
  • 是的,它正在工作。如果你不介意,你能解释一下正则表达式模式吗?
【解决方案3】:

你可以使用正则表达式:

^(\d+)\s+.*\D\s+(?=((?:\d+(?:\.\d+)?\s*)+)$)

Demo

设置多行标志(或在开头插入(?m))。

对于行(例如)

0   NS-100ML(GLASS) IV 1 19.25

捕获组 1 将包含 0,捕获组 2 将包含 1 19.25。用从两个捕获组的内容派生的所需字符串替换该行应该是一件容易的事。

Python 的正则表达式引擎执行以下操作。

^                # match beginning of line
(\d+)            # match 1+ digits in cap grp 1
\s+              # match 1+ spaces
.*               # match 0+ chars
\D               # match a char other than a digit
\s+              # match 1+ spaces
(?=              # begin positive lookahead
  (              # begin cap grp 2
    (?:          # begin non-cap grp
      \d+        # match 1+ digits
      (?:\.\d+)  # match '.' followed by 1+ digits in non-cap grp
      ?          # optionally match non-cap grp
      \s*        # match 0+ spaces
    )            # end non-cap grp
    +            # match non-cap grp 1+ times
  )              # end cap grp 2
  $              # match end of line
)                # end positive lookahead

【讨论】:

  • 嗨,感谢您的解决方案,如果我在单词之间有数字怎么办?我不想选他们。请再次检查问题。
【解决方案4】:

我假设数字由一个空格分隔。如果你只有一行,我会使用:

def extract_numbers(row):
    entries = row['text'].split(' ')
    ans = []
    while entries:
        item = entries.pop()
        try:
            num = float(item)
        except ValueError:
            # we encountered non-numerical data
            return ans
        else:
            ans = [num] + ans
   return ans

现在你有了一个数据框。

df['numbers'] = df['text'].apply(extract_numbers)

【讨论】:

    【解决方案5】:

    这是一个使用str.splitexplode的方法

    print(df2)
    
                                           text
    0  NS-100ML(GLASS) IV 1.00 4.95 63.36 96.45
    1      India into SI  8.0 52.30 53.46 12.03
    2                INJ 2.0 63.80 34.30 56.36 
    
    
    number_list = pd.to_numeric(df2["text"].str.split(" ").explode(), errors="coerce").dropna().groupby(
        level=0
    ).agg(list)
    

    print(number_list)
    
    0    [1.0, 4.95, 63.36, 96.45]
    1    [8.0, 52.3, 53.46, 12.03]
    2     [2.0, 63.8, 34.3, 56.36]
    Name: text, dtype: object
    

    【讨论】:

    • 嗨,感谢您的解决方案,如果我在单词之间有数字怎么办?我不想选他们。请再次检查问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-03
    • 2012-12-10
    相关资源
    最近更新 更多