在panda中,下面的代码会将col1中的字符串拆分成许多列。在polars中有办法做到这一点吗?
d = {'col1': ["a/b/c/d", "a/b/c/d"]} df= pd.DataFrame(data=d) df[["a","b","c","d"]]=df["col1"].str.split('/',expand=True)
5f0d552i1#
这里有一个算法,它将自动调整所需的列数--而且性能应该很好。让我们从这个数据开始,注意我特意添加了空字符串""和一个null值--以显示算法如何处理这些值,而且拆分字符串的数量变化很大。
""
import polars as pl df = pl.DataFrame( { "my_str": ["cat", "cat/dog", None, "", "cat/dog/aardvark/mouse/frog"], } ) df
shape: (5, 1) ┌─────────────────────────────┐ │ my_str │ │ --- │ │ str │ ╞═════════════════════════════╡ │ cat │ ├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤ │ cat/dog │ ├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤ │ null │ ├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤ │ │ ├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤ │ cat/dog/aardvark/mouse/frog │ └─────────────────────────────┘
下面的算法可能比您需要的多一点,但您可以根据需要编辑/删除/添加。一个二个一个一个
我们首先分配一个行号id(稍后会用到),然后使用split分隔字符串,注意,分隔后的字符串形成一个列表。
id
split
( df .with_row_count('id') .with_column(pl.col("my_str").str.split("/").alias("split_str")) )
shape: (5, 3) ┌─────┬─────────────────────────────┬────────────────────────────┐ │ id ┆ my_str ┆ split_str │ │ --- ┆ --- ┆ --- │ │ u32 ┆ str ┆ list[str] │ ╞═════╪═════════════════════════════╪════════════════════════════╡ │ 0 ┆ cat ┆ ["cat"] │ ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤ │ 1 ┆ cat/dog ┆ ["cat", "dog"] │ ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤ │ 2 ┆ null ┆ null │ ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤ │ 3 ┆ ┆ [""] │ ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤ │ 4 ┆ cat/dog/aardvark/mouse/frog ┆ ["cat", "dog", ... "frog"] │ └─────┴─────────────────────────────┴────────────────────────────┘
接下来,我们将使用explode将每个字符串放在它自己的行上(注意id列如何跟踪每个字符串来自的原始行)。
explode
( df .with_row_count('id') .with_column(pl.col("my_str").str.split("/").alias("split_str")) .explode("split_str") )
shape: (10, 3) ┌─────┬─────────────────────────────┬───────────┐ │ id ┆ my_str ┆ split_str │ │ --- ┆ --- ┆ --- │ │ u32 ┆ str ┆ str │ ╞═════╪═════════════════════════════╪═══════════╡ │ 0 ┆ cat ┆ cat │ ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤ │ 1 ┆ cat/dog ┆ cat │ ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤ │ 1 ┆ cat/dog ┆ dog │ ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤ │ 2 ┆ null ┆ null │ ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤ │ 3 ┆ ┆ │ ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤ │ 4 ┆ cat/dog/aardvark/mouse/frog ┆ cat │ ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤ │ 4 ┆ cat/dog/aardvark/mouse/frog ┆ dog │ ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤ │ 4 ┆ cat/dog/aardvark/mouse/frog ┆ aardvark │ ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤ │ 4 ┆ cat/dog/aardvark/mouse/frog ┆ mouse │ ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤ │ 4 ┆ cat/dog/aardvark/mouse/frog ┆ frog │ └─────┴─────────────────────────────┴───────────┘
下一步,我们将生成列名,我选择将每一列命名为string_XX,其中XX是相对于原始字符串的偏移量。我使用了方便的zfill表达式,使1变为01(这确保了如果您决定稍后对列进行排序,string_02位于string_10之前)。您可以根据需要在此步骤中替换您自己的命名。
string_XX
XX
zfill
1
01
string_02
string_10
( df .with_row_count('id') .with_column(pl.col("my_str").str.split("/").alias("split_str")) .explode("split_str") .with_column( ("string_" + pl.arange(0, pl.count()).cast(pl.Utf8).str.zfill(2)) .over("id") .alias("col_nm") ) )
shape: (10, 4) ┌─────┬─────────────────────────────┬───────────┬───────────┐ │ id ┆ my_str ┆ split_str ┆ col_nm │ │ --- ┆ --- ┆ --- ┆ --- │ │ u32 ┆ str ┆ str ┆ str │ ╞═════╪═════════════════════════════╪═══════════╪═══════════╡ │ 0 ┆ cat ┆ cat ┆ string_00 │ ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤ │ 1 ┆ cat/dog ┆ cat ┆ string_00 │ ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤ │ 1 ┆ cat/dog ┆ dog ┆ string_01 │ ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤ │ 2 ┆ null ┆ null ┆ string_00 │ ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤ │ 3 ┆ ┆ ┆ string_00 │ ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤ │ 4 ┆ cat/dog/aardvark/mouse/frog ┆ cat ┆ string_00 │ ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤ │ 4 ┆ cat/dog/aardvark/mouse/frog ┆ dog ┆ string_01 │ ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤ │ 4 ┆ cat/dog/aardvark/mouse/frog ┆ aardvark ┆ string_02 │ ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤ │ 4 ┆ cat/dog/aardvark/mouse/frog ┆ mouse ┆ string_03 │ ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤ │ 4 ┆ cat/dog/aardvark/mouse/frog ┆ frog ┆ string_04 │ └─────┴─────────────────────────────┴───────────┴───────────┘
在下一步中,我们将使用pivot函数将每个字符串放置到各自的列中。
pivot
( df .with_row_count('id') .with_column(pl.col("my_str").str.split("/").alias("split_str")) .explode("split_str") .with_column( ("string_" + pl.arange(0, pl.count()).cast(pl.Utf8).str.zfill(2)) .over("id") .alias("col_nm") ) .pivot( index=['id', 'my_str'], values='split_str', columns='col_nm', ) )
shape: (5, 7) ┌─────┬─────────────────────────────┬───────────┬───────────┬───────────┬───────────┬───────────┐ │ id ┆ my_str ┆ string_00 ┆ string_01 ┆ string_02 ┆ string_03 ┆ string_04 │ │ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │ │ u32 ┆ str ┆ str ┆ str ┆ str ┆ str ┆ str │ ╞═════╪═════════════════════════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╡ │ 0 ┆ cat ┆ cat ┆ null ┆ null ┆ null ┆ null │ ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤ │ 1 ┆ cat/dog ┆ cat ┆ dog ┆ null ┆ null ┆ null │ ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤ │ 2 ┆ null ┆ null ┆ null ┆ null ┆ null ┆ null │ ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤ │ 3 ┆ ┆ ┆ null ┆ null ┆ null ┆ null │ ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤ │ 4 ┆ cat/dog/aardvark/mouse/frog ┆ cat ┆ dog ┆ aardvark ┆ mouse ┆ frog │ └─────┴─────────────────────────────┴───────────┴───────────┴───────────┴───────────┴───────────┘
剩下要做的就是使用fill_null将null值替换为空字符串""。注意,我在col表达式中使用了一个regex表达式,以便只针对名称以"string_"开头的列。(根据其他数据,您可能不希望在数据中的任何地方都用""替换null。)
fill_null
null
col
sd2nnvve2#
可以使用apply()方法
apply()
import polars as pl from polars import col df = pl.DataFrame({ 'col1': ["a/b/c/d", "e/f/j/k"] }) print(df)
df:
df
shape: (2, 1) ┌─────────┐ │ col1 │ │ --- │ │ str │ ╞═════════╡ │ a/b/c/d │ ├╌╌╌╌╌╌╌╌╌┤ │ e/f/j/k │ └─────────┘
使用apply()
df = df.with_columns([ col('col1'), *[col('col1').apply(lambda s, i=i: s.split('/')[i]).alias(col_name) for i, col_name in enumerate(['a', 'b', 'c', 'd'])] # or without 'for' # col('col1').apply(lambda s: s.split('/')[0]).alias('a'), # col('col1').apply(lambda s: s.split('/')[1]).alias('b'), # col('col1').apply(lambda s: s.split('/')[2]).alias('c'), # col('col1').apply(lambda s: s.split('/')[3]).alias('d') ]) print(df)
shape: (2, 5) ┌─────────┬─────┬─────┬─────┬─────┐ │ col1 ┆ a ┆ b ┆ c ┆ d │ │ --- ┆ --- ┆ --- ┆ --- ┆ --- │ │ str ┆ str ┆ str ┆ str ┆ str │ ╞═════════╪═════╪═════╪═════╪═════╡ │ a/b/c/d ┆ a ┆ b ┆ c ┆ d │ ├╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤ │ e/f/j/k ┆ e ┆ f ┆ j ┆ k │ └─────────┴─────┴─────┴─────┴─────┘
它工作,但可能有更准确的方式)
5us2dqdw3#
通过这种方法,可以进行字符串拆分,将col1转换为字符串列表,然后循环遍历列表,并使用.arr.get将每个元素提取到单独的列中
.arr.get
(df .with_column(pl.col("col1").str.split("/")) .with_columns( [pl.col("col1").arr.get(i).alias(str(i)) for i in range(len(df[0,"col1"].split('/'))) ] ) )
一个挑战是你是否会在列表的每一行中拥有相同数量的元素,在这个解决方案中,我假设你已经并且已经取得了列表第一行的长度来执行循环。
vq8itlhq4#
您可以使用struct数据类型,如本文所述:https://stackoverflow.com/a/74219166:
import pandas as pl df = pl.DataFrame({ "my_str": ["cat", "cat/dog", None, "", "cat/dog/aardvark/mouse/frog"], }) df.select(pl.col('my_str').str.split('/') .arr.to_struct(n_field_strategy="max_width")).unnest('my_str')
注意,必须使用n_field_strategy="max_width",否则unnest()将只创建1列。
n_field_strategy="max_width"
unnest()
4条答案
按热度按时间5f0d552i1#
这里有一个算法,它将自动调整所需的列数--而且性能应该很好。
让我们从这个数据开始,注意我特意添加了空字符串
""
和一个null值--以显示算法如何处理这些值,而且拆分字符串的数量变化很大。算法
下面的算法可能比您需要的多一点,但您可以根据需要编辑/删除/添加。
一个二个一个一个
工作原理
我们首先分配一个行号
id
(稍后会用到),然后使用split
分隔字符串,注意,分隔后的字符串形成一个列表。接下来,我们将使用
explode
将每个字符串放在它自己的行上(注意id
列如何跟踪每个字符串来自的原始行)。下一步,我们将生成列名,我选择将每一列命名为
string_XX
,其中XX
是相对于原始字符串的偏移量。我使用了方便的
zfill
表达式,使1
变为01
(这确保了如果您决定稍后对列进行排序,string_02
位于string_10
之前)。您可以根据需要在此步骤中替换您自己的命名。
在下一步中,我们将使用
pivot
函数将每个字符串放置到各自的列中。剩下要做的就是使用
fill_null
将null
值替换为空字符串""
。注意,我在col
表达式中使用了一个regex表达式,以便只针对名称以"string_"开头的列。(根据其他数据,您可能不希望在数据中的任何地方都用""
替换null。)sd2nnvve2#
可以使用
apply()
方法df
:使用
apply()
df
:它工作,但可能有更准确的方式)
5us2dqdw3#
通过这种方法,可以进行字符串拆分,将col1转换为字符串列表,然后循环遍历列表,并使用
.arr.get
将每个元素提取到单独的列中一个挑战是你是否会在列表的每一行中拥有相同数量的元素,在这个解决方案中,我假设你已经并且已经取得了列表第一行的长度来执行循环。
vq8itlhq4#
您可以使用struct数据类型,如本文所述:https://stackoverflow.com/a/74219166:
注意,必须使用
n_field_strategy="max_width"
,否则unnest()
将只创建1列。