Мой код:
df = pd.read_xml(
path_or_buffer=PATH,
xpath = "//Data",
compression = "gzip"
)
Я использую функцию Pandas read_xml()
для чтения данных формата xml.gz
. Я использую версию Pandas 1.3.2
. Когда я попытался прочитать данные, Панды прочитали данные неправильно.
Данные выглядят так, как показано ниже. И colA
, и colB
должны быть строкой.
1-й файл данных:
<Data>
<colA>abc</colA>
<colB>168E3</colB>
</Data>
<Data>
<colA>def</colA>
</Data>
2-й файл данных:
<Data>
<colA>ghi</colA>
<colB>23456</colB>
</Data>
<Data>
<colA>jkl</colA>
</Data>
Когда я использую функцию read_xml()
, это выглядит следующим образом:
1-й фрейм данных:
colA: abc, def
colB: 168000.0, None
2-й фрейм данных:
colA: ghi, jkl
colB: 23456.0, None
Я хочу прочитать данные в формате string
, но в пандах dtype
нет аргумента 1.3.2
. Я хочу знать:
Обратите внимание, что я могу использовать только эту версию Pandas и не могу ее обновить.
Определите dtype
столбцов в pandas:
(NaN будет читаться как класс «NoneType», но вы можете использовать astype() позже.
import pandas as pd
from io import StringIO
xml_ = """\
<root>
<Data>
<colA>abc</colA>
<colB>168E3</colB>
</Data>
<Data>
<colA>def</colA>
</Data>
</root>"""
file = StringIO(xml_)
df = pd.read_xml(file, xpath = ".//Data", dtype = {'colA': str, 'colB': str})
print(df.astype(str).applymap(type))
Выход:
colA colB
0 <class 'str'> <class 'str'>
1 <class 'str'> <class 'str'>
Но последний оператор с astyp() в любом случае должен работать.
Это работает, но поскольку данные вначале анализируются неправильно (например, 168E3
-> 168000.0
), даже astype()
работает, они станут строкой 168000.0
.
Если возможно, перейдите на более новую версию панд. Я использую версию: 2.0.3.
Спасибо за ваш комментарий, но я не могу обновиться до более новой версии. Я пытаюсь найти, есть ли какое-либо решение, которое может настроить тип данных по умолчанию/отключить его.
Применение простого преобразования xslt для принудительного ввода строкового типа для каждого значения может сработать (у меня нет pandas 1.3.2 для тестирования, но работает на pandas 2.x). Кажется невозможным получить канонический ответ, учитывая ограничение версии. Альтернативой может быть анализ XML-документа с помощью lxml и заполнение кадра данных вручную.
Преобразование объединяет нечисловой символ, который позже удаляется.
XSLT
<xsl:stylesheet version = "1.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
<xsl:template match = "node()">
<xsl:copy>
<xsl:apply-templates select = "node()"/>
<xsl:value-of select = "'|'"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Питон
import pandas as pd
from io import StringIO
xml_ = """\
<root>
<Data>
<colA>abc</colA>
<colB>168E3</colB>
</Data>
<Data>
<colA>def</colA>
</Data>
</root>"""
file = StringIO(xml_)
df = pd.read_xml(xml_, stylesheet = "/home/lmc/tmp/test.xslt" )
print(df.apply(lambda x: x.str[:-1]))
Результат
colA colB
0 abc 168E3
1 def None
Исходный результат
colA colB
0 abc| 168E3|
1 def| None
Если вы можете установить другие библиотеки, вы можете прочитать XML-файл как dict
с помощью xmltodict, а затем использовать его для создания кадра данных pandas.
import gzip
import xmltodict
import pandas as pd
def read_xml_as_dict(gzip_path):
with gzip.open(gzip_path, "r") as f:
xml = f.read()
return xmltodict.parse(xml)
data = read_xml_as_dict(PATH)
df = pd.DataFrame(data["root"]["Data"])
Если вы не можете установить xmltodict
, вы можете разобрать его с помощью xml.etree.ElementTree аналогичным образом:
import gzip
import xml.etree.ElementTree as ET
import pandas as pd
def read_xml_as_dict(gzip_path):
with gzip.open(gzip_path, "r") as f:
xml = f.read()
root = ET.fromstring(xml)
data_list = []
for item in root.findall("Data"):
data_dict = {}
for child in item:
data_dict[child.tag] = child.text
data_list.append(data_dict)
return data_list
data = read_xml_as_dict(PATH)
df = pd.DataFrame(data)
Оба будут печатать:
colA colB
0 abc 168E3
1 def NaN
Столбцы будут иметь dtype object
:
df.info()
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 colA 2 non-null object
1 colB 1 non-null object
Спасибо за ответ, но в
dtype
нет аргумента в пользуread_xml()
. pandas.pydata.org/pandas-docs/version/1.3.2/reference/api/…