如何在Python3.x中将“bytes”对象转换为文本字符串在Pandas数据框中?

46

我有一个Python3.x的pandas数据框,其中某些列是字符串,表示为字节(类似于Python2.x)

import pandas as pd
df = pd.DataFrame(...)
df
       COLUMN1         ....
0      b'abcde'        ....
1      b'dog'          ....
2      b'cat1'         ....
3      b'bird1'        ....
4      b'elephant1'    ....

使用 df.COLUMN1 按列访问时,我看到 Name: COLUMN1, dtype: object

但是,如果按元素访问,则为“字节”对象。

df.COLUMN1.ix[0].dtype
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'bytes' object has no attribute 'dtype'

我应该如何将它们转换为“普通”的字符串?也就是说,我该如何去掉 b'' 前缀?

5个回答

77
你可以使用向量化的 str.decode 来将字节字符串解码为普通字符串:
df['COLUMN1'].str.decode("utf-8")

要为多个列执行此操作,您可以仅选择str列:

str_df = df.select_dtypes([np.object])

将它们全部转换:

str_df = str_df.stack().str.decode('utf-8').unstack()

您可以用原始数据框的列替换已转换的列:

for col in str_df:
    df[col] = str_df[col]

我也遇到了同样的问题,但我的数据框包含其他不是字节(例如数组)的np对象。有没有办法只设置字节列? - pnina

6
结合@EdChum和@Yu Zhou的答案,更简单的解决方案是:
for col, dtype in df.dtypes.items():
    if dtype == np.object:  # Only process byte object columns.
        df[col] = df[col].apply(lambda x: x.decode("utf-8"))

3
这里不应该使用"Apply"。使用df[col].str.decode('utf-8') - Mad Physicist
那么对于不是任何字符串的 object 呢? - jtlz2
DeprecationWarning: np.object 是内置对象 object 的一个已弃用的别名。 - jtlz2

5

我在一个数据框中遇到了一些列要么全部是字符串,要么是字符串和字节的混合。通过对 @Christabella Irwanto 提供的解决方案进行了轻微修改来解决这个问题:(像 @Mad Physicist 建议的那样,我更喜欢使用 str.decode('utf-8'))

for col, dtype in df.dtypes.items():
        if dtype == object:  # Only process object columns.
            # decode, or return original value if decode return Nan
            df[col] = df[col].str.decode('utf-8').fillna(df[col]) 


>>> df[col]
0        Element
1     b'Element'
2         b'165'
3            165
4             25
5             25

>>> df[col].str.decode('utf-8').fillna(df[col])
0     Element
1     Element
2         165
3         165
4          25
5          25
6          25

(将np.object替换为object以适应最近的numpy版本)


1
DeprecationWarning: np.object 是内置的 object 的一个已弃用的别名。 - jtlz2
是的,自从numpy 1.24版本以后,np.object就不再起作用了。但是根据numpy弃用信息,将其替换为"object"即可解决问题。 - Jan
是的,自从numpy版本1.24开始,np.object不再起作用了。但是根据numpy弃用信息,将其替换为object可以解决这个问题。 - undefined

1

我在尝试解决一个问题时偶然发现了这个帖子,但我的情况更一般,因为有些值可能是str类型,而另一些值则是bytes类型。借鉴之前的解决方案,我按照以下方式实现了选择性解码,从而得到了一个所有值都是str类型的Series。(python 3.6.9,pandas 1.0.5)

>>> import pandas as pd
>>> ser = pd.Series(["value_1".encode("utf-8"), "value_2"])
>>> ser.values
array([b'value_1', 'value_2'], dtype=object)
>>> ser2 = ser.str.decode("utf-8")
>>> ser[~ser2.isna()] = ser2
>>> ser.values
array(['value_1', 'value_2'], dtype=object)

也许存在更方便/高效的一行代码来实现这个用例?起初我认为可以通过传递“errors” kwarg 到 str.decode 中来实现,但我没有找到一个被记录的值。
编辑:确实可以用一行代码实现相同的功能,但我想到的方法大约需要25%的时间(针对长度为10^4和10^6的Series进行测试),但是可能不会复制。例如:
ser[ser.apply(type) == bytes] = ser.str.decode("utf-8")

1
df['COLUMN1'].apply(lambda x: x.decode("utf-8"))

4
你好,欢迎来到SO。多写一点文字会更好哦;-) - Alexander

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