TL;DR:使用.tolist()。不要使用list()
如果我们看一下.tolist()的源代码,在底层,list()函数是在数据框架中的底层数据上调用的,因此两者应该产生相同的输出。
然而,看起来tolist()针对Python标量的列进行了优化,因为我发现在列上调用list()比调用tolist()慢10倍。为了记录,我试图将一个非常大的dataframe中的一列json字符串转换为一个列表,list()正在花费它的甜蜜时间。这启发了我去测试这两个方法的运行时。
仅供参考,不需要调用.to_numpy()或获取.values属性,因为数据帧列/系列对象已经实现了.tolist()方法。此外,由于numpy数组的存储方式,list()和tolist()将为数值列提供不同类型的标量(至少)。例如,
type(list(df['budget'].values)[0]) # numpy.int64
type(df['budget'].values.tolist()[0]) # int
下面的perfplot显示了这两种方法在不同pandas dtype Series对象上的运行时差异。基本上,它显示了以下两个方法之间的运行时差异:
list(df['some_col']) # list()
df['some_col'].tolist() # .tolist()
如您所见,无论列/Series的大小,对于数值和对象dtype列/Series, .tolist()方法都比list()快得多。这里没有包括浮点型和bool型dtype列的图,但它们与这里显示的int型dtype列的图非常相似。另外,包含列表的对象dtype列的图与这里显示的字符串列的图非常相似。扩展类型,如'Int64Dtype', 'StringDtype', 'Float64Dtype'等也显示了类似的模式。
另一方面,对于datetime、timedelta和Categorical dtype列,这两种方法实际上没有什么区别。
用于生成上述图表的代码:
from perfplot import plot
kernels = [lambda s: list(s), lambda s: s.tolist()]
labels = ['list()', '.tolist()']
n_range = [2**k for k in range(4, 20)]
xlabel = 'Rows in DataFrame'
eq_chk = lambda x,y: all([x,y])
numeric = lambda n: pd.Series(range(5)).repeat(n)
string = lambda n: pd.Series(['some word', 'another word', 'a word']).repeat(n)
datetime = lambda n: pd.to_datetime(pd.Series(['2012-05-14', '2046-12-31'])).repeat(n)
timedelta = lambda n: pd.to_timedelta(pd.Series([1,2]), unit='D').repeat(n)
categorical = lambda n: pd.Series(pd.Categorical([1, 2, 3, 1, 2, 3])).repeat(n)
for n, f in [('Numeric', numeric), ('Object dtype', string),
('Datetime', datetime), ('Timedelta', timedelta),
('Categorical', categorical)]:
plot(setup=f, kernels=kernels, labels=labels, n_range=n_range,
xlabel=xlabel, title=f'{n} column', equality_check=eq_chk);