Polars 是否支持从嵌套字典创建数据框?
Does Polars support creating a dataframe from a nested dictionary?
我正在尝试从字典 (mainDict) 创建一个 polars 数据框,其中 mainDict 的值之一是字典对象列表 (nestedDicts)。当我尝试这样做时,我收到一个我不知道其含义的错误(见下文)。但是,pandas 确实允许我使用 mainDict 创建数据框。
我不确定我是否做错了什么,是否是一个错误,或者这个操作是否只是不受 polars 的支持。我不太担心找到解决方法,因为它应该很简单(欢迎提出建议),但如果可能的话我想这样做。
我在 google colab 上使用 polars 版本 0.13.38(问题也发生在 VScode 上,python 版本 3.9.6 和 windows 10 ).下面是重现问题及其输出的代码示例。谢谢!
输入:
import polars as pl
import pandas as pd
template = { 'a':['A', 'AA'],
'b':['B', 'BB'],
'c':['C', 'CC'],
'd':[{'D1':'D2'}, {'DD1':'DD2'}]}
#create a dataframe using pandas
df_pandas = pd.DataFrame(template)
print(df_pandas)
#create a dataframe using polars
df_polars = pl.DataFrame(template)
print(df_polars)
输出:
a b c d
0 A B C {'D1': 'D2'}
1 AA BB CC {'DD1': 'DD2'}
---------------------------------------------------------------------------
ComputeError Traceback (most recent call last)
<ipython-input-9-2abdc86d91da> in <module>()
12
13 #create a dataframe using polars
---> 14 df_polars = pl.DataFrame(template)
15 print(df_polars)
3 frames
/usr/local/lib/python3.7/dist-packages/polars/internals/frame.py in __init__(self, data, columns, orient)
300
301 elif isinstance(data, dict):
--> 302 self._df = dict_to_pydf(data, columns=columns)
303
304 elif isinstance(data, np.ndarray):
/usr/local/lib/python3.7/dist-packages/polars/internals/construction.py in dict_to_pydf(data, columns)
400 return PyDataFrame(data_series)
401 # fast path
--> 402 return PyDataFrame.read_dict(data)
403
404
/usr/local/lib/python3.7/dist-packages/polars/internals/series.py in __init__(self, name, values, dtype, strict, nan_to_null)
225 self._s = self.cast(dtype, strict=True)._s
226 elif isinstance(values, Sequence):
--> 227 self._s = sequence_to_pyseries(name, values, dtype=dtype, strict=strict)
228 elif _PANDAS_AVAILABLE and isinstance(values, (pd.Series, pd.DatetimeIndex)):
229 self._s = pandas_to_pyseries(name, values)
/usr/local/lib/python3.7/dist-packages/polars/internals/construction.py in sequence_to_pyseries(name, values, dtype, strict)
241 if constructor == PySeries.new_object:
242 try:
--> 243 return PySeries.new_from_anyvalues(name, values)
244 # raised if we cannot convert to Wrap<AnyValue>
245 except RuntimeError:
ComputeError: struct orders must remain the same
您收到的错误是因为您的词典列表不符合 Polars 中 struct
的 Series
的预期。更具体地说,您的两个词典 {'D1':'D2'}
和 {'DD1':'DD2'}
被映射到 Polars 中的两种不同类型的结构,因此不兼容包含在同一个 Series
.
中
我首先需要解释结构...
极地:结构
在 Polars 中,字典被映射到一个叫做 struct
的东西。结构是 有序、命名 类型化数据的集合。 (在这方面,结构很像只有一行的 Polars DataFrame
。)
在结构中:
- 每个字段必须有一个唯一的字段名称
- 每个字段都有一个数据类型
- 结构中字段的顺序很重要
Polars:将字典映射到结构
当字典映射到结构时(例如,在 DataFrame
构造函数中),字典中的每个键都映射到结构中的字段名称,并且相应的字典值被分配给该字段的值结构中的字段。
此外,字典中键的顺序很重要:struct
字段的创建顺序与字典中键的顺序相同。在 Python 中,很容易忘记字典中的键是有序的。
Changed in version 3.7: Dictionary order is guaranteed to be insertion order. This behavior was an implementation detail of CPython from 3.6.
极地:Series/Lists 个结构
这是您的输入在 Polars 中遇到问题的地方。 只有在以下情况下,结构集合才能包含在同一个 Series
中:
- 结构体的字段数相同
- 字段名称相同
- 字段顺序相同
- 每个结构的每个字段的数据类型都相同。
在您的输入中,{'D1':'D2'}
映射到一个结构,其中一个字段的字段名称为“D1”,值为“D2”。但是,{'DD1':'DD2'}
映射到一个结构,其中一个字段的字段名称为“DD1”,值为“DD2”。因此,生成的结构不兼容以包含在相同的 Series
中。他们的字段名称不匹配。
在这种情况下,Polars far 比 Pandas 更挑剔,这允许具有任意 key-value 对的词典出现在同一列中。
一般来说,您会发现 Polars 对数据结构和数据类型的看法远比 Pandas 强。 (部分原因是 performance-related。)
解决方法
您的示例的一个解决方法是更改您的词典,以便它们以相同的顺序包含相同的键。例如:
template = {
"a": ["A", "AA"],
"b": ["B", "BB"],
"c": ["C", "CC"],
"d": [{"D1": "D2", "DD1": None}, {"D1": None, "DD1": "DD2"}],
}
pl.DataFrame(template)
shape: (2, 4)
┌─────┬─────┬─────┬──────────────┐
│ a ┆ b ┆ c ┆ d │
│ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ str ┆ str ┆ struct[2] │
╞═════╪═════╪═════╪══════════════╡
│ A ┆ B ┆ C ┆ {"D2",null} │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ AA ┆ BB ┆ CC ┆ {null,"DD2"} │
└─────┴─────┴─────┴──────────────┘
另一个简单的解决方法是先将数据导入 Pandas,然后将 Pandas DataFrame 导入 Polars。导入过程将为您完成这项工作。
template = {
"a": ["A", "AA"],
"b": ["B", "BB"],
"c": ["C", "CC"],
"d": [{"D1": "D2"}, {"DD1": "DD2"}],
}
pl.DataFrame(pd.DataFrame(template))
>>> pl.DataFrame(pd.DataFrame(template))
shape: (2, 4)
┌─────┬─────┬─────┬──────────────┐
│ a ┆ b ┆ c ┆ d │
│ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ str ┆ str ┆ struct[2] │
╞═════╪═════╪═════╪══════════════╡
│ A ┆ B ┆ C ┆ {"D2",null} │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ AA ┆ BB ┆ CC ┆ {null,"DD2"} │
└─────┴─────┴─────┴──────────────┘
可能还有其他解决方法,但这取决于您的具体数据和需求。
我正在尝试从字典 (mainDict) 创建一个 polars 数据框,其中 mainDict 的值之一是字典对象列表 (nestedDicts)。当我尝试这样做时,我收到一个我不知道其含义的错误(见下文)。但是,pandas 确实允许我使用 mainDict 创建数据框。
我不确定我是否做错了什么,是否是一个错误,或者这个操作是否只是不受 polars 的支持。我不太担心找到解决方法,因为它应该很简单(欢迎提出建议),但如果可能的话我想这样做。
我在 google colab 上使用 polars 版本 0.13.38(问题也发生在 VScode 上,python 版本 3.9.6 和 windows 10 ).下面是重现问题及其输出的代码示例。谢谢!
输入:
import polars as pl
import pandas as pd
template = { 'a':['A', 'AA'],
'b':['B', 'BB'],
'c':['C', 'CC'],
'd':[{'D1':'D2'}, {'DD1':'DD2'}]}
#create a dataframe using pandas
df_pandas = pd.DataFrame(template)
print(df_pandas)
#create a dataframe using polars
df_polars = pl.DataFrame(template)
print(df_polars)
输出:
a b c d
0 A B C {'D1': 'D2'}
1 AA BB CC {'DD1': 'DD2'}
---------------------------------------------------------------------------
ComputeError Traceback (most recent call last)
<ipython-input-9-2abdc86d91da> in <module>()
12
13 #create a dataframe using polars
---> 14 df_polars = pl.DataFrame(template)
15 print(df_polars)
3 frames
/usr/local/lib/python3.7/dist-packages/polars/internals/frame.py in __init__(self, data, columns, orient)
300
301 elif isinstance(data, dict):
--> 302 self._df = dict_to_pydf(data, columns=columns)
303
304 elif isinstance(data, np.ndarray):
/usr/local/lib/python3.7/dist-packages/polars/internals/construction.py in dict_to_pydf(data, columns)
400 return PyDataFrame(data_series)
401 # fast path
--> 402 return PyDataFrame.read_dict(data)
403
404
/usr/local/lib/python3.7/dist-packages/polars/internals/series.py in __init__(self, name, values, dtype, strict, nan_to_null)
225 self._s = self.cast(dtype, strict=True)._s
226 elif isinstance(values, Sequence):
--> 227 self._s = sequence_to_pyseries(name, values, dtype=dtype, strict=strict)
228 elif _PANDAS_AVAILABLE and isinstance(values, (pd.Series, pd.DatetimeIndex)):
229 self._s = pandas_to_pyseries(name, values)
/usr/local/lib/python3.7/dist-packages/polars/internals/construction.py in sequence_to_pyseries(name, values, dtype, strict)
241 if constructor == PySeries.new_object:
242 try:
--> 243 return PySeries.new_from_anyvalues(name, values)
244 # raised if we cannot convert to Wrap<AnyValue>
245 except RuntimeError:
ComputeError: struct orders must remain the same
您收到的错误是因为您的词典列表不符合 Polars 中 struct
的 Series
的预期。更具体地说,您的两个词典 {'D1':'D2'}
和 {'DD1':'DD2'}
被映射到 Polars 中的两种不同类型的结构,因此不兼容包含在同一个 Series
.
我首先需要解释结构...
极地:结构
在 Polars 中,字典被映射到一个叫做 struct
的东西。结构是 有序、命名 类型化数据的集合。 (在这方面,结构很像只有一行的 Polars DataFrame
。)
在结构中:
- 每个字段必须有一个唯一的字段名称
- 每个字段都有一个数据类型
- 结构中字段的顺序很重要
Polars:将字典映射到结构
当字典映射到结构时(例如,在 DataFrame
构造函数中),字典中的每个键都映射到结构中的字段名称,并且相应的字典值被分配给该字段的值结构中的字段。
此外,字典中键的顺序很重要:struct
字段的创建顺序与字典中键的顺序相同。在 Python 中,很容易忘记字典中的键是有序的。
Changed in version 3.7: Dictionary order is guaranteed to be insertion order. This behavior was an implementation detail of CPython from 3.6.
极地:Series/Lists 个结构
这是您的输入在 Polars 中遇到问题的地方。 只有在以下情况下,结构集合才能包含在同一个 Series
中:
- 结构体的字段数相同
- 字段名称相同
- 字段顺序相同
- 每个结构的每个字段的数据类型都相同。
在您的输入中,{'D1':'D2'}
映射到一个结构,其中一个字段的字段名称为“D1”,值为“D2”。但是,{'DD1':'DD2'}
映射到一个结构,其中一个字段的字段名称为“DD1”,值为“DD2”。因此,生成的结构不兼容以包含在相同的 Series
中。他们的字段名称不匹配。
在这种情况下,Polars far 比 Pandas 更挑剔,这允许具有任意 key-value 对的词典出现在同一列中。
一般来说,您会发现 Polars 对数据结构和数据类型的看法远比 Pandas 强。 (部分原因是 performance-related。)
解决方法
您的示例的一个解决方法是更改您的词典,以便它们以相同的顺序包含相同的键。例如:
template = {
"a": ["A", "AA"],
"b": ["B", "BB"],
"c": ["C", "CC"],
"d": [{"D1": "D2", "DD1": None}, {"D1": None, "DD1": "DD2"}],
}
pl.DataFrame(template)
shape: (2, 4)
┌─────┬─────┬─────┬──────────────┐
│ a ┆ b ┆ c ┆ d │
│ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ str ┆ str ┆ struct[2] │
╞═════╪═════╪═════╪══════════════╡
│ A ┆ B ┆ C ┆ {"D2",null} │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ AA ┆ BB ┆ CC ┆ {null,"DD2"} │
└─────┴─────┴─────┴──────────────┘
另一个简单的解决方法是先将数据导入 Pandas,然后将 Pandas DataFrame 导入 Polars。导入过程将为您完成这项工作。
template = {
"a": ["A", "AA"],
"b": ["B", "BB"],
"c": ["C", "CC"],
"d": [{"D1": "D2"}, {"DD1": "DD2"}],
}
pl.DataFrame(pd.DataFrame(template))
>>> pl.DataFrame(pd.DataFrame(template))
shape: (2, 4)
┌─────┬─────┬─────┬──────────────┐
│ a ┆ b ┆ c ┆ d │
│ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ str ┆ str ┆ struct[2] │
╞═════╪═════╪═════╪══════════════╡
│ A ┆ B ┆ C ┆ {"D2",null} │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ AA ┆ BB ┆ CC ┆ {null,"DD2"} │
└─────┴─────┴─────┴──────────────┘
可能还有其他解决方法,但这取决于您的具体数据和需求。