Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 熊猫:如何从CSV读取字节和非字节列并解码字节列?_Python_Python 3.x_Pandas_Csv_Binary Data - Fatal编程技术网

Python 熊猫:如何从CSV读取字节和非字节列并解码字节列?

Python 熊猫:如何从CSV读取字节和非字节列并解码字节列?,python,python-3.x,pandas,csv,binary-data,Python,Python 3.x,Pandas,Csv,Binary Data,我有一个.csv文件,有4列:2个整数列、1个字节数组列和一个日期列。这个字节数组列有一个二进制文本,我需要将其解码为一个普通的utf-8字符串 下面是my.csv的外观: id1 id2 text date 1 2 0x202020312045584D4F2841292E205 2020-01-01 3 4 0x20312020455843454C454E

我有一个.csv文件,有4列:2个整数列、1个字节数组列和一个日期列。这个字节数组列有一个二进制文本,我需要将其解码为一个普通的utf-8字符串

下面是my.csv的外观:

id1   id2   text                                       date
 1     2    0x202020312045584D4F2841292E205           2020-01-01
 3     4    0x20312020455843454C454E                  2020-05-01
当我简单地使用pd.read_csv()时:

输出:

id1       id2              text                   date
24228   35649098    0x202020312045584D4F2841292E2   2020-05-04
24298   97780137    0x20312020455843454C454E54C38   2020-05-04
df.info():

但是,我需要普通的字符串,所以我尝试只解码这个列,但我无法使它工作。以下是我已经尝试过的:

试验1:

df.loc[:,'transformedText'] = df.text.str.decode('utf-8')
输出: transformedText列全部为NaN

试验2:

df.loc[:,'transformedText'] = df.text.str.encode('utf-8').str.decode('utf-8')
输出: transformedText列保留字节数组字符串

试验3:

df.loc[:,'transformedText'] = df.text.str.encode('ascii').str.decode('utf-8')
输出: transformedText列保留字节数组字符串

为了进一步调查这个问题,我检查了刚编码字符串时发生的情况: df.loc[:,'transformedText']=df.text.str.encode('ascii')

输出: 它所做的只是在我的字符串上添加一个b'(例如b'0x20202031204584D4F2841292E2')

我相信解码不起作用的原因是因为read_csv没有将我的列识别为字节数组列,而是将我的列识别为字符串列。尽管如此,我对此并不确定

我需要的输出是:

id1       id2              text                                date
24228   35649098    A normal string that a human can read 1  2020-05-04
24298   97780137    A normal string that a human can read 2  2020-05-04
另外,我对二进制文件有点陌生,所以任何东西都有帮助

我已经查看了下面的链接,但找不到答案:





确保您实际拥有正确的十六进制字符串(您的一些示例中有奇数个十六进制数字,这将导致下面的代码失败)

然后:


CSV中的数据与
pandas
读取的数据之间似乎存在一些不一致。这是您从文件中共享的第一行:

 1     2    0x202020312045584D4F2841292E205           2020-01-01
请注意,字符串被编码为十六进制(以
0x
开头),因此,它需要偶数位数才能正确解码。上面的示例有29位数字(不包括
0x
),这意味着无法正确解码

然而,我注意到在加载代码时可能会出现问题(或者只是输入错误)。两行二进制字符串在读取之前和之后都以相同的数字开头,但它们的最终数字不同。见第一条:

0x202020312045584D4F2841292E205  # Before
0x202020312045584D4F2841292E2    # After
第二个:

0x20312020455843454C454E       # Before
0x20312020455843454C454E54C38  # After
此外,在加载到pandas之前和之后,日期和
id
列也不同。检查pandas是否正确加载了您的数据会很有趣

无论如何,如果您有十六进制数据字符串,您可以通过执行以下操作对其进行解码:

df['Decoded'] = df['text'].str[2:].apply(lambda s: bytes.fromhex(s).decode('utf-8')
如果将此列改为数字,则可以执行以下操作:

df['Decoded'] = df['text'].apply(lambda s: bytes.fromhex(hex(s)[2:]).decode('utf-8')
它已成功解码文本中的以下二进制字符串:

0x202020312045584D4F2841292E20 # First row without the last digit
0x20312020455843454C454E  # Second row
返回:

0       1 EXMO(A).
1        1  EXCELEN
这两个词在葡萄牙语中都是“几乎”的词:
EXMO(A)
是Excelentíssimo(A)的缩写,而
EXCELEN
是一个不完整的词,可以是Excelência、Excelente或类似的词(我也是巴西人,所以很高兴看到一些非英语单词被解码)


正如你所看到的,你的数据有一些问题,但我们可以通过某种方式解码其中的一部分。如果您有任何进一步的问题,请告诉我们您是否成功解码了您的文本。

此答案的目的是(希望)填补潜在的理解空白,即为什么您的尝试和明显的实际努力没有导致解决方案

目前,@PierreD和@Ralubrusto的优秀答案很好地解释了这个解决方案


在丛林中寻找鲨鱼: 这个问题表明你正在研究如何解码“二进制”字符串。问题是,两个字符串都不是二进制字符串,而是十六进制字符串。这就是标题——不幸的是,你找错了地方

有什么区别?十六进制字符串是表示二进制数据的一种方法

  • 二进制:由两个符号组成的数字系统,
    0
    1
  • 十六进制:由16个符号(十六进制(6)+十进制(10))、
    0-9
    A-F
    组成的数字系统。可以“计数”为
    0、1、…、8、9、A、B、…、E、F
8位二进制代码就是8个字符(
01001001
)。而等效的8位十六进制代码(
49
)是两个字符。您提供的十六进制字符串之一是28个字符。如果将其转换为二进制,它将是112个字符!因此,十六进制系统是一种“缩短”二进制字符串的方法,以便于表示

提供两种数据类型的简单比较


十六进制到ASCII: 本示例的目的是说明为什么
.encode()
.decode()
函数只执行部分作业

使用以下步骤,手动将十六进制字符串转换为ASCII字符串很容易:

  • 将十六进制转换为二进制(编码函数在此停止)
  • 将二进制转换为十进制
  • 通过
此示例显示手动转换:

0x49 (hex) --> 0100 1001 (binary) --> 73 (decimal) --> I (ascii)

    # .encode() stops here ^^^

总结: 二进制字符串
b'mystring'
b'49'
和十六进制字符串
'0x49'
是不同的东西;其中十六进制字符串可以是二进制值的表示形式


我希望这有助于解释为什么你的尝试不幸没有成功——尽管付出了巨大的努力。

Hey@Ralubrusto!谢谢你的回答!这种不一致性实际上是我的错,文本比这大得多,是一个角色文档转换为这种类型的编码。所以为了简化,我只复制了文本的开头,否则它将是一个巨大的字符串,我认为这会使我对问题的解释复杂化。我不知道,回到过去,这将是一个问题:/
df['Decoded'] = df['text'].apply(lambda s: bytes.fromhex(hex(s)[2:]).decode('utf-8')
0x202020312045584D4F2841292E20 # First row without the last digit
0x20312020455843454C454E  # Second row
0       1 EXMO(A).
1        1  EXCELEN
0x49 (hex) --> 0100 1001 (binary) --> 73 (decimal) --> I (ascii)

    # .encode() stops here ^^^