我有以下用于操作不起作用的极坐标数据框的代码
import polars as pl
import xml.etree.ElementTree as ET
# create a sample dataframe
df = pl.DataFrame({
'A': [1, 2, 3],
'B': ['<p>some text</p><p>bla</p>', '<p>some text<p><p>foo</p>', '<p>some text<p>']
})
def func(mystring):
return mystring*2
def func2(xml_string):
root = ET.fromstring(xml_string)
text_list = []
for elem in root.iter():
text = elem.text.strip() if elem.text else ''
text_list.append(text)
return test_list
# create a sample series to add as a new column
df = df.with_columns((pl.col("A").map_batches(lambda x: func(x)).alias('new_col')))
df = df.with_columns((pl.col("B").map_batches(lambda x: func2(x)).alias('new_col2')))
print(df)
添加列的第一行有效,即添加 new_col
但是第二个不起作用。
我得到的错误是:
计算错误:类型错误:需要类似字节的对象,而不是“系列”
基本上,我的用例是包含 XML 字符串的列,我必须对其进行操作,创建 XML 对象并提取信息。
我该如何继续?
您的第一个示例之所以有效,是因为
*2
是矢量化的。
例如,如果你这样做
func(pl.Series([1,2,3,4,5]))
然后你会得到一系列原始乘以 2 的值。
您的
func2
未矢量化。要使用 map
,那么您的函数需要对整个列进行操作并返回类似系列的内容。
例如:
from lxml import etree as ET
def func2_series(xml_strings):
ret_List=[]
for xml_string in xml_strings:
root = ET.fromstring(xml_string, ET.XMLParser(recover=True))
text_list = []
for elem in root.iter():
text = elem.text.strip() if elem.text else ''
text_list.append(text)
ret_List.append(text_list)
return pl.Series(ret_List)
随后
dfpl.with_columns(pl.col("B").map(func2_series).alias('new_col2'))
会起作用的。
如果你有的话
def func2(xml_string):
root = ET.fromstring(xml_string, ET.XMLParser(recover=True))
text_list = []
for elem in root.iter():
text = elem.text.strip() if elem.text else ''
text_list.append(text)
return text_list
然后你可以使用 apply,然后 Polars 会为你做循环。
dfpl.with_columns(pl.col("B").apply(func2))
顺便说一句,如果您传递的函数接受您所拥有的确切
x
,则不需要使用 lambda。换句话说,只要你有 .map(lambda x: func2(x))
,你就可以做 .map(func2)
。如果您需要转换参数,那么 lambda 就会发挥作用。
如评论中所述,使用
.apply
而不是 .map
。另外,如果您只想要字符串列表,我建议使用 beautifulsoup
s 方法 .stripped_strings
:
import polars as pl
from bs4 import BeautifulSoup
# create a sample dataframe
dfpl = pl.DataFrame({
'A': [1, 2, 3],
'B': ['<p>some text</p><p>bla</p>', '<p>some text<p><p>foo</p>', '<p>some text<p>']
})
def func(mystring):
return mystring*2
def func2(xml_string):
soup = BeautifulSoup(xml_string, 'html.parser')
return list(soup.stripped_strings)
# create a sample series to add as a new column
dfpl=dfpl.with_columns([(pl.col("A").apply(lambda x: func(x)).alias('new_col'))])
dfpl=dfpl.with_columns([(pl.col("B").apply(lambda x: func2(x)).alias('new_col2'))])
print(dfpl)
打印:
shape: (3, 4)
┌─────┬────────────────────────────┬─────────┬──────────────────────┐
│ A ┆ B ┆ new_col ┆ new_col2 │
│ --- ┆ --- ┆ --- ┆ --- │
│ i64 ┆ str ┆ i64 ┆ list[str] │
╞═════╪════════════════════════════╪═════════╪══════════════════════╡
│ 1 ┆ <p>some text</p><p>bla</p> ┆ 2 ┆ ["some text", "bla"] │
│ 2 ┆ <p>some text<p><p>foo</p> ┆ 4 ┆ ["some text", "foo"] │
│ 3 ┆ <p>some text<p> ┆ 6 ┆ ["some text"] │
└─────┴────────────────────────────┴─────────┴──────────────────────┘