我有兩個表(從資料庫中提取的 csv 檔案),一個包含訂單,第二個包含專案,它們與訂單表有關。我需要從這兩個檔案構建一個 XML 檔案以具有這種結構(由于可讀性而簡化):
<ORDERS>
<ORDER>
<ORDER_ID>11039515178</ORDER_ID>
<CUSTOMER_ID>394556458</CUSTOMER_ID>
<ITEMS>
<ITEM>
<PRODUCT_ID>1401817</PRODUCT_ID>
<AMOUNT>2</AMOUNT>
</ITEM>
<ITEM>
<PRODUCT_ID>1138857</PRODUCT_ID>
<AMOUNT>10</AMOUNT>
</ITEM>
<ITEM>
<PRODUCT_ID>4707595</PRODUCT_ID>
<AMOUNT>15</AMOUNT>
</ITEM>
</ITEMS>
</ORDER>
</ORDERS>
我使用此代碼生成 XML 物件。它被簡化為代碼的主要結構,因此易于閱讀:
import xml.etree.ElementTree as ET
import pandas as pd
order = pd.read_csv("order.csv", encoding='utf8', keep_default_na=False, dtype=str)
order_item = pd.read_csv("order_item.csv", encoding='utf8', keep_default_na=False, dtype=str)
# create XML
xml_orrder = ET.Element('ORDERS')
for row in order.itertuples():
item = ET.SubElement(xml_orrder, 'ORDER')
o_id = ET.Element('ORDER_ID')
o_id.text = row.order_id
item.append(o_id)
customer = ET.Element('CUSTOMER_ID')
customer.text = row.customer_id
item.append(customer)
order_item_id = order_item[order_item['order_id'] == row.order_id]
items = ET.SubElement(item, 'ITEMS')
for order_row in order_item_id.itertuples():
single_item = ET.SubElement(items, 'ITEM')
item_id = ET.Element('PRODUCT_ID')
item_id.text = order_row.product_id
single_item.append(item_id)
quantity = ET.Element('AMOUNT')
quantity.text = order_row.quantity_ordered
single_item.append(quantity)
我的問題是它的運行時間長得令人難以置信(每 1000 個訂單大約需要 15 分鐘,每個訂單大約有 20 件商品)。我想我在這里做錯了什么,但我無法找出答案。有沒有辦法加快速度?使用另一個庫?我嘗試使用 itertuples() 而不是 iterrows()。但這不是很有幫助。
編輯:
這就是我的資料的樣子:
order = pd.DataFrame({"order_id": range(1000000,1000010,1),
"customer_id": np.random.RandomState(0).randint(1000,2000,10)})
order_item = pd.DataFrame({"order_id": np.random.RandomState(0).randint(1000000,1000010,100),
"product_id": np.random.RandomState(0).randint(1000,2000,100),
"amount": np.random.RandomState(0).randint(1,100,100)})
order_item.sort_values(by="order_id",inplace=True,ignore_index=True)
uj5u.com熱心網友回復:
在撰寫 XML 或 HTML 時,以文本方式撰寫通常更快,而不是增加構建記憶體中 XML 檔案的費用。您可以直接撰寫檔案或使用模板語言(如 jinja 2)。以下是使用多行 f 字串撰寫具有所需間距的檔案的示例。由于 XML 不關心換行符或漂亮的列印,我傾向于在沒有額外間距的情況下撰寫。
代碼有點難看,但對于所有模板來說都是如此,恕我直言。
import pandas as pd
order = pd.read_csv("order.csv", encoding='utf8', keep_default_na=False, dtype=str)
order_item = pd.read_csv("order_item.csv", encoding='utf8', keep_default_na=False, dtype=str)
with open("out.xml", "w") as outfile:
outfile.write("""\
<ORDERS>
""")
for row in order.itertuples():
outfile.write(
f"""\
<ORDER>
<ORDER_ID>{row.order_id}</ORDER_ID>
<CUSTOMER_ID>f{row.customer_id)</CUSOMTER_ID>
""")
outfile.write(f"""\
<ITEMS>
""")
order_item_id = order_item[order_item['order_id'] == row.order_id]
for order_row in order_item_id.itertuples():
outfile.write(f"""\
<ITEM>
<PRODUCT_ID>{order_row.product_id}</PRODUCT_ID>
<AMOUNT>{order_row.quantity_ordered}</AMOUNT>
</ITEM>
"""
outfile.write("""\
</ITEMS>
""")
outfile.write("""\
</ORDERS>
</ORDER>"""
uj5u.com熱心網友回復:
我不確定你的資料是什么樣的,所以我希望這對你有用,我花了幾秒鐘來處理 ~5000 行:
import pandas as pd
import lxml.etree as et
df_order = pd.read_csv("order.csv", encoding='utf8', keep_default_na=False, dtype=str)
df_order_item = pd.read_csv("order_items.csv", encoding='utf8', keep_default_na=False, dtype=str)
new_orders = df_order.merge(df_order_item, 'left', left_on='order_id', right_on='order_id')
orders = et.Element('ORDERS')
for order_id in new_orders['order_id'].unique():
rows = new_orders[new_orders['order_id'] == order_id]
customer_id = int(rows['customer_id'].unique())
order = et.SubElement(orders, 'ORDER')
o_id = et.SubElement(order, 'ORDER_ID')
o_id.text = order_id
c_id = et.SubElement(order, 'CUSTOMER_ID')
c_id.text = str(customer_id)
items = et.SubElement(order, 'ITEMS')
for product in rows.itertuples():
item = et.SubElement(items, 'ITEM')
p_id = et.SubElement(item, 'PRODUCT_ID')
p_id.text = product.product_id
amount = et.SubElement(item, 'AMOUNT')
amount.text = product.quantity_ordered
uj5u.com熱心網友回復:
顯然 pandasto_xml不處理這種層次結構。您可以將其中的一部分直接寫入 xml 檔案并to_xml在分組的子 df 上使用:
df = order.merge(order_item, on='order_id')
with open('output.xml', 'w') as f:
f.write('<ORDERS>')
for (ord_id, cust_id), sub_df in df.groupby(['order_id', 'customer_id']):
f.write(f'\n<ORDER>\n<ORDER_ID>{ord_id}</ORDER_ID>\n<CUSTOMER_ID>{cust_id}</CUSTOMER_ID>\n')
f.write(sub_df.to_xml(root_name='ITEMS', row_name='ITEM', xml_declaration=False, elem_cols=['product_id', 'amount'], index=False))
f.write(f'\n</ORDER>')
f.write('\n</ORDERS>')
如果您發現任何性能改進,請告訴我們!
注意:您也可以使用 kwarg parser=('lxml' 或 'etree')選擇您的 xml 決議器
uj5u.com熱心網友回復:
我已經嘗試了上面提到的一些方法,但是顯著加快整個程序的一件事是使這些嵌套<ITEMS>標簽已經在資料庫中。我們正在使用雪花,我使用 LISTAGG 分組函式在 order_item 表上做了一個簡單的分組:
CREATE OR REPLACE TABLE "wrk_order_item" AS
SELECT
"order_id",
'<ITEMS>' || LISTAGG('<ITEM><PRODUCT_ID>' || "product_id" || '</PRODUCT_ID>'
|| '<AMOUNT>' || "quantity_ordered" || '</AMOUNT>'
|| '<PRICE>' || "sell_price" || '</PRICE></ITEM>') || '</ITEMS>' AS "items"
FROM "ORDER_ITEM"
GROUP BY "order_id";
將它與訂單表連接起來,并在 python 腳本中的訂單表上的每次迭代中洗掉專案資料框的創建。兩個代碼(雪花、python)現在都在幾秒鐘內完成。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/471900.html
上一篇:使用Python進行XML排序
下一篇:XSL為行內容器結果創建fo表
