Y. *_*Gao 6 python performance dataframe pandas
与简单的实现相比,Pandas to_dict("records") 的性能似乎要差得多。下面是我的实现的代码片段:
\ndef fast_to_dict_records(df):\n data = df.values.tolist()\n columns = df.columns.tolist() \n return [\n dict(zip(columns, datum))\n for datum in data\n ]\n
Run Code Online (Sandbox Code Playgroud)\n要比较性能,请尝试以下代码片段:
\nimport pandas as pd\nimport numpy as np\n\ndf_test = pd.DataFrame(\n np.random.normal(size=(10000, 300)),\n columns=range(300)\n)\n\n%timeit df_test.to_dict('records')\n%timeit fast_to_dict_records(df_test)\n
Run Code Online (Sandbox Code Playgroud)\n输出是:
\n2.21 s \xc2\xb1 71.2 ms per loop (mean \xc2\xb1 std. dev. of 7 runs, 1 loop each)\n293 ms \xc2\xb1 15.8 ms per loop (mean \xc2\xb1 std. dev. of 7 runs, 1 loop each)\n
Run Code Online (Sandbox Code Playgroud)\n也就是说,我的实现比 pandas 本机实现快约 7.5 倍。此外,应该很容易验证这两种方法提供相同的结果。我还测试了不同大小的数据帧的性能,并且似乎我的实现始终优于其对应的实现(尽管幅度可能有所不同)。
\n我很好奇我在这里错过了什么吗?我只是不相信 pandas 的本机实现性能(在我的印象中相当有竞争力)可以被一个不那么复杂的替代方案击败......
\nTL;DR: Pandas 大部分是用纯 Python编写的,就像您的实现一样,尽管它经常在内部使用矢量化 Numpy 调用来加速计算。不幸的是,这里的情况并非如此。因此,Pandas 的实现效率很低。您的实现速度更快,但需要更多内存。
to_list
你可以在这里找到它的实现。它使用内部迭代数据itertuples
(有关其代码,请参见此处)。截至 2021 年 3 月 12 日,生成的(稍微简化的)Pandas 代码如下:
def maybe_box_native(value: Scalar) -> Scalar:
if is_datetime_or_timedelta_dtype(value): # branch never taken here
value = maybe_box_datetimelike(value)
elif is_float(value): # branch always taken here
value = float(value) # slow manual conversion for EACH values!
elif is_integer(value):
value = int(value)
elif is_bool(value):
value = bool(value)
return value
def pandas_to_list(df):
# From itertuples:
fields = list(df.columns)
arrays = [df.iloc[:, k] for k in range(len(df.columns))]
tmpRes = zip(*arrays)
# From to_list:
columns = df.columns.tolist()
rows = (dict(zip(columns, row)) for row in tmpRes)
return [dict((k, maybe_box_native(v)) for k, v in row.items()) for row in rows]
Run Code Online (Sandbox Code Playgroud)
当 Pandas 在内部使用 Python 生成器时,您的实现会在内存中生成一个大的临时列表to_list
。在大多数简单情况下,这个列表在实践中不应该成为问题,因为dict
最终应该会更大。
但是,to_list
(在您的实现中)还可以使用内部矢量化 Numpy调用有效地转换 Numpy 类型,而 Pandas 使用非常慢的方法。事实上, Pandas使用纯 Python 函数和缓慢的 if/else对所有值进行一一检查和转换...因此,Pandas 实现速度较慢也就不足为奇了。话虽这么说,请注意您的代码对于日期的行为可能有所不同。maybe_box_native
当前的 Pandas 实现效率低下,将来显然可以改进(可能不需要更多内存)。