我有一列包含8000行的列,我需要创建一个新列,该列的值将从现有列中提取。
字符串显示如下:
TP-ETU06-01-525-W-133
我想从该字符串中创建两个新列,其中从第二个字符串ETU06中提取第一个新列的值,第二个从最后一个字符串133中提取第二个。
我通过使用以下方式完成此操作:
df["sys_no"] = df.apply(lambda x:x["test_no"].split("-")[1] if (pd.notnull(x["test_no"]) and x["test_no"]!="" and len(x["test_no"].split("-"))>0) else None,axis=1)
df["package_no"] = df.apply(lambda x:x["test_no"].split("-")[-1] if (pd.notnull(x["test_no"]) and x["test_no"]!="" and len(x["test_no"].split("-"))>0) else None,axis=1)
它实际上可以正常工作,但是现有的列具有不跟随其他列的随机字符串。因此,如果出现随机字符串,我想在新列中保留空白。
我应该如何更改脚本?
谢谢
答案 0 :(得分:1)
使用Series.str.contains
作为掩码,然后将值除以Series.str.split
,并通过按掩码仅索引已过滤的行来选择第二和最后一个值:
print (df)
test_no
0 temp data
1 NaN
2 TP-ETU06-01-525-W-133
mask = df["test_no"].str.contains('-', na=False)
splitted = df["test_no"].str.split("-")
df.loc[mask, "sys_no"] = splitted[mask].str[1]
df.loc[mask, "package_no"] = splitted[mask].str[-1]
print (df)
test_no sys_no package_no
0 temp data NaN NaN
1 NaN NaN NaN
2 TP-ETU06-01-525-W-133 ETU06 133
答案 1 :(得分:1)
此方法使用 regex 和命名的捕获组,仅用两行代码即可找到并提取感兴趣的字符串。
split
的好处:确实不需要正则表达式。但是,从数据验证的角度来看,使用正则表达式有助于防止“杂散”数据蔓延。使用“盲” split()
函数可将数据分割为(一个字符)。但是如果源数据已更改怎么办?拆分功能对此无视。鉴于使用正则表达式将有助于突出显示问题,因为模式根本不匹配。是的,您可能会收到一条错误消息-但这是一件好事,因为您会收到有关数据格式更改的警报,从而有机会解决此问题或更新正则表达式模式。
此外,正则表达式提供了一种可靠的解决方案,因为该模式与整个字符串匹配,并且该模式之外的任何内容都将被忽略-就像问题中提到的示例一样。
如果您想对正则表达式模式本身进行一些解释,只需添加一条注释,我将更新答案进行解释。
test_no
0 TP-ETU05-01-525-W-005
1 TP-ETU06-01-525-W-006
2 TP-ETU07-01-525-W-007
3 TP-ETU08-01-525-W-008
4 TP-ETU09-01-525-W-009
5 NaN
6 NaN
7 otherstuff
import re
exp = re.compile(r'^[A-Z]{2}-(?P<sys_no>[A-Z]{3}\d{2})-\d{2}-\d{3}-[A-Z]-(?P<package_no>\d{3})$')
df[['sys_no', 'package_no']] = df['test_no'].str.extract(exp, expand=True)
test_no sys_no package_no
0 TP-ETU05-01-525-W-005 ETU05 005
1 TP-ETU06-01-525-W-006 ETU06 006
2 TP-ETU07-01-525-W-007 ETU07 007
3 TP-ETU08-01-525-W-008 ETU08 008
4 TP-ETU09-01-525-W-009 ETU09 009
5 NaN NaN NaN
6 NaN NaN NaN
7 otherstuff NaN NaN