>我有一个熊猫数据帧的列,我想根据分隔符的第二个实例将其拆分并扩展为一个新的数据帧。我是根据分隔符的最后一个实例进行拆分的,但不幸的是,~80k 行中有少数实例有 4 个"_"而不是 3。
例如,我有一个包含多列的数据帧,其中我想拆分为新数据帧的数据帧如下所示:
df.head()
gene
0 NM_000000_foo_blabla
1 NM_000001_bar
我想拆分和扩展它,使其分离为:
(需要(
df2.head()
col1 col2
0 NM_000000 foo_bar
1 NM_000001 foo
在使用我当前的代码时:
df2 = df['gene'].str.rsplit('_', 1, expand=True).rename(lambda x: f'col{x + 1}', axis=1)
我明白这个:
(实际(
df2.head()
col1 col2
0 NM_000000_foo bar
1 NM_000001 foo
有没有一种简单的方法可以实现我修改我已经使用的代码行?我尝试在 rsplit 中玩拆分的数量,但无法达到我想要的结果。谢谢!
由于您的数据似乎定义得相当好,因此您可以使用正则表达式在分隔符的第二个实例上进行提取。
df['gene'].str.extract(r'(?:[^_]+_){2}(.*)')
0
0 foo_blabla
1 bar
您可以将其概括为任何分隔符,并使用简单的函数将其匹配任意次数:
def build_regex(delimiter, num_matches=1):
return rf'(?:[^{delimiter}]+{delimiter}){{{num_matches}}}(.*)'
>>> build_regex('_', 2)
'(?:[^_]+_){2}(.*)'
>>> df['gene'].str.extract(build_regex('_', 2))
0
0 foo_blabla
1 bar
>>> df['gene'].str.extract(build_regex('_', 3))
0
0 blabla
1 NaN
正则表达式解释
(?: # non capture group
[^_]+ # match anything but _ one or more times
_ # match _
){2} # match this group 2 times
( # start of capture group 1
.* # match anything greedily
) # end of matching group 1
如果不能保证在前两个分隔符中的任何一个之前有文本,您还可以使非断言匹配 0 次或更多次:
(?:[^_]*_){2}(.*)
只需将第二个'_'
替换为您的自定义除尘器并在其上split
即可
df.gene.str.replace(r'([^_]+_[^_]+)_', r'1|').str.split('|', expand=True)
Out[488]:
0 1
0 NM_000000 foo_blabla
1 NM_000001 bar