在 Pandas 数据框中给字符串添加前导零

127

我有一个Pandas数据框,其中前3列是字符串:

         ID        text1    text 2
0       2345656     blah      blah
1          3456     blah      blah
2        541304     blah      blah        
3        201306       hi      blah        
4   12313201308    hello      blah         

我想在ID前面添加前导零:

                ID    text1    text 2
0  000000002345656     blah      blah
1  000000000003456     blah      blah
2  000000000541304     blah      blah        
3  000000000201306       hi      blah        
4  000012313201308    hello      blah 

我已经尝试过:

df['ID'] = df.ID.zfill(15)
df['ID'] = '{0:0>15}'.format(df['ID'])

请问您能否解释一下 '{0:0>15}'.format(df['ID']) 的工作原理。 - spd
8个回答

151

4
加入df['ID'] = df['ID'].astype(str)以处理ID为数值型的情况,然后运行df['ID'] = df['ID'].str.zfill(15)。 - Je Je
1
为了获得更通用和可定制的解决方案,可以使用 str.pad;您可以查看这个答案 - Ric S
我在运行这个程序时遇到了一个错误,提示整数类型没有字符串属性。 - max_settings

121

尝试:

df['ID'] = df['ID'].apply(lambda x: '{0:0>15}'.format(x))

甚至更多

df['ID'] = df['ID'].apply(lambda x: x.zfill(15))

32
第一个不需要用 lambdaapply('{:0>15}'.format) 也可以。 - DSM
1
@DSM 很好。我不知道那个。 - Rohit
可以通过单行初始化来实现,详见下面的答案。 - Danil
1
@Rohit如果字符串中有小数或字母,代码会如何更改?例如,将2.0a转换为02.0a需要什么,可以使用lambda x: x.zfill(2)来实现吗? - Andreuccio
你能解释一下为什么使用15吗?这个数字的意义是什么?如果我只想加一个‘0’怎么办? - Murtaza Haji
嗨@MurtazaHaji,15是字符串的期望总长度。 - Robert Alexander

19

只需在初始化时使用一个单行代码,即可实现。只需使用转换器参数。

df = pd.read_excel('filename.xlsx', converters={'ID': '{:0>15}'.format})

这样您就可以将代码长度缩短一半 :)

PS:read_csv 也有这个参数。


19

从Python 3.6+开始,您还可以使用f字符串:

df['ID'] = df['ID'].map(lambda x: f'{x:0>15}')

性能与 df ['ID'] .map('{:0>15}'。format)相当或稍差。另一方面,f-strings允许更复杂的输出,并且您可以通过列表推导式更有效地使用它们。

性能基准测试

# Python 3.6.0, Pandas 0.19.2

df = pd.concat([df]*1000)

%timeit df['ID'].map('{:0>15}'.format)                  # 4.06 ms per loop
%timeit df['ID'].map(lambda x: f'{x:0>15}')             # 5.46 ms per loop
%timeit df['ID'].astype(str).str.zfill(15)              # 18.6 ms per loop

%timeit list(map('{:0>15}'.format, df['ID'].values))    # 7.91 ms per loop
%timeit ['{:0>15}'.format(x) for x in df['ID'].values]  # 7.63 ms per loop
%timeit [f'{x:0>15}' for x in df['ID'].values]          # 4.87 ms per loop
%timeit [str(x).zfill(15) for x in df['ID'].values]     # 21.2 ms per loop

# check results are the same
x = df['ID'].map('{:0>15}'.format)
y = df['ID'].map(lambda x: f'{x:0>15}')
z = df['ID'].astype(str).str.zfill(15)

assert (x == y).all() and (x == z).all()

1
尝试使用6GB文件进行了测试,比其他方法快得多,而且更高效。感谢@jpp。 - anky
1
在某些情况下,这样做更快。尝试使用 df['text1'].map('{:015}'.format) - rpanai
1
@user32185,谢谢你。我发现使用applymap的差别很小,可能与设置有关。我已经更新了我的答案中的时间和建议,因为没有使用lambdastr.format似乎更好。 - jpp
@user32185,我宁愿专注于字符串操作函数。你的问题是另一个问题,但如果你看到了很大的区别(我没有),那就是一个好问题。如果你认为这很重要,你可以提出一个新问题,这样我们就有了一个可以指向的规范和理由。 - jpp
@user32185,我是说这并不相关(几微秒证明不了什么)。我只是碰巧最后使用了map(并非有意为之)。对我来说,我可以使用任何一个而不改变目的或影响。如果你认为这很重要,那么我建议你指出一些证据或理由。 - jpp
显示剩余4条评论

15

如果你遇到以下错误:

Pandas错误:只能对使用np.object_ dtype的字符串值使用.str访问器

df['ID'] = df['ID'].astype(str).str.zfill(15)

10
如果您想要一个更加可定制的解决方案来解决这个问题,可以尝试使用 pandas.Series.str.pad
df['ID'] = df['ID'].astype(str).str.pad(15, side='left', fillchar='0')

str.zfill(n) 是一个特殊情况,相当于 str.pad(n, side='left', fillchar='0')

的等价表达式。


2

1
"

rjust 对我很有用:

"
df['ID']= df['ID'].str.rjust(15,'0')

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