使用pandas将字符串分割成数字和文本

5

设置

我有一个包含化学同位素符号的列'iso'的pandas数据框,例如 '4He'、'16O'、'197Au'。 我想使用matplotlib中的annotate()函数将许多(但不是全部)同位素标记在图上。 标签格式应该带有上标的原子质量。 我可以用LaTeX样式格式化来做到这一点:

axis.annotate('$^{4}$He', xy=(x, y), xycoords='data')

我可以为每个我想标记的同位素编写几十个annotate()语句,但我更愿意自动化。

问题

如何从我的iso列中提取同位素编号和名称?

有了这些提取出来的部分,我就可以制作标签。 假设我们将它们倒入变量NumSym中。 现在我可以循环遍历我的同位素并执行以下操作:

for i in list_of_isotopes:
  (Num, Sym) = df[df.iso==i].iso.str.MISSING_STRING_METHOD(???)
  axis.annotate('$^{%s}$%s' %(Num, Sym), xy=(x[Num], y[Num]), xycoords='data')

我想,我可以使用字符串方法来解决这个问题。但是我一直在尝试使用和以及一些不同的模式,但无法获得所需的效果。


也许这可以帮助您拆分 iso 列。它将为split返回的每个标记创建一列。您能提供要拆分的数据和匹配模式的示例吗?df = pd.DataFrame('part1_part2', index=range(0,3), columns=['iso']) df['iso'].str.split('_', expand=True) - Romain
那需要我的列已经有一个下划线...但它没有。 - Paul T.
使用可改进的 regexp 分割字符串,检查我的答案。 - Romain
5个回答

12

这是我使用split的答案。所使用的正则表达式可以改进,我对这种事情很不擅长 :-)

(\d+)代表整数,而([A-Za-z]+)代表字符串。

df = pd.DataFrame({'iso': ['4He', '16O', '197Au']})
result = df['iso'].str.split('(\d+)([A-Za-z]+)', expand=True)
result = result.loc[:,[1,2]]
result.rename(columns={1:'x', 2:'y'}, inplace=True)
print(result)

产生

     x   y
0    4  He
1   16   O
2  197  Au

1
这个很好扩展。我可以轻松地在原始数据框中运行所有2000多个同位素。此外,我还将创建的列添加到了现有的数据框中。 - Paul T.
太好了,我刚刚对我的答案进行了一点小改进!我仍然不知道为什么会生成两列额外的列。我有点对“regexp”过敏。 - Romain
@Fei Yuan,回复您的编辑建议,expand参数在文档中提到是“版本0.16.1中新增的”。也许这就是为什么代码在您的环境中无法工作的原因。 - Romain
1
[A-z] 匹配的不仅仅是 ASCII 字母。我将其更改为 [A-Za-z] - Wiktor Stribiżew
1
这很好地扩展,速度快,并且是最干净的方法。 - msarafzadeh
显示剩余2条评论

1
接受的答案给了我正确的方向,但我认为正确的pandas函数应该是extract。这样只返回匹配的正则表达式,省去了之后的切片操作。
df = pd.DataFrame({'iso': ['4He', '16O', '197Au']})
df[['num', 'element']] = df['iso'].str.extract('(\d+)([A-Za-z]+)', expand=True)
print(df)

提供

     iso  num element
0    4He    4      He
1    16O   16       O
2  197Au  197      Au

0
我会使用简单的字符串操作,避免正则表达式的麻烦。
isotopes = ['4He', '16O', '197Au']
def get_num(isotope):
    return filter(str.isdigit, isotope)

def get_sym(isotope):
    return isotope.replace(get_num(isotope),'')

def get_num_sym(isotope):
    return (get_num(isotope),get_sym(isotope))


for isotope in isotopes:
    num,sym = get_num_sym(isotope)
    print num,sym

0
要提取同位素符号的数字和元素,您可以使用正则表达式(简称:regex)与Python的re模块相结合。 正则表达式查找数字和之后查找字符,这些字符被分组并可使用组名访问。 如果正则表达式匹配,则可以提取数据并.format()所需的注释字符串:
#!/usr/bin/env python3
# coding: utf-8

import re

iso_num = '16O'

preg = re.compile('^(?P<num>[0-9]*)(?P<element>[A-Za-z]*)$')
m = preg.match(iso_num)

if m:
    num = m.group('num')
    element = m.group('element')

    note = '$^{}${}'.format(num, element)

    # axis.annotate(note, xy=(x, y), xycoords='data')

0

你尝试过使用strip()吗?也许你可以考虑一下:

import string

for i in list_of_isotopes:
  Num = df[df.iso==i].iso.str.strip(string.ascii_letters)
  Sym = df[df.iso==i].iso.str.strip(string.digits)
  axis.annotate('$^%s$%s' %(Num, Sym), xy=(x[Num], y[Num]), xycoords='data')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接