pandas:DataFrame.mean()非常慢。如何更快地计算列的平均值?

9

我有一个相当大的CSV文件,它包含9917530行(不包括标题),以及54列。列是实数或整数,只有一个包含日期。文件中有一些NULL值,在我加载到pandas DataFrame后会被转换为nan,我是这样做的:

import pandas as pd
data = pd.read_csv('data.csv')

加载完成后,我认为速度非常快,因为它只花了大约30秒的时间(与Unix工具wc计算行数的时间几乎相同),该进程占用了约4GB的RAM(磁盘上文件的大小为2.2GB)。到目前为止一切顺利。

然后我尝试做以下操作:

column_means = data.mean()

这个进程的占用内存很快就增长到了约22GB。我还能看到处理器(一个核心)非常地繁忙——整整三个小时,之后我杀掉了这个进程,因为我需要使用机器做其他事情。我的电脑是一台带有Linux系统、有两个处理器,每个处理器有4个核心,总共是8个核心,还有32GB的RAM,我无法相信计算列均值会花费这么长的时间。
有人能解释一下为什么DataFrame.mean()这么慢吗?更重要的是,有什么更好的方法来计算这种类型文件的列均值吗?我没有以最佳方式加载文件吗?我应该使用不同于DataFrame.mean()的函数或完全不同的工具吗?
提前感谢大家。
编辑:以下是df.info()所显示的内容:
<class 'pandas.core.frame.DataFrame'>
Int64Index: 9917530 entries, 0 to 9917529
Data columns (total 54 columns):
srch_id                        9917530  non-null values
date_time                      9917530  non-null values
site_id                        9917530  non-null values
visitor_location_country_id    9917530  non-null values
visitor_hist_starrating        505297  non-null values
visitor_hist_adr_usd           507612  non-null values
prop_country_id                9917530  non-null values
prop_id                        9917530  non-null values
prop_starrating                9917530  non-null values
prop_review_score              9902900  non-null values
prop_brand_bool                9917530  non-null values
prop_location_score1           9917530  non-null values
prop_location_score2           7739150  non-null values
prop_log_historical_price      9917530  non-null values
position                       9917530  non-null values
price_usd                      9917530  non-null values
promotion_flag                 9917530  non-null values
srch_destination_id            9917530  non-null values
srch_length_of_stay            9917530  non-null values
srch_booking_window            9917530  non-null values
srch_adults_count              9917530  non-null values
srch_children_count            9917530  non-null values
srch_room_count                9917530  non-null values
srch_saturday_night_bool       9917530  non-null values
srch_query_affinity_score      635564  non-null values
orig_destination_distance      6701069  non-null values
random_bool                    9917530  non-null values
comp1_rate                     235806  non-null values
comp1_inv                      254433  non-null values
comp1_rate_percent_diff        184907  non-null values
comp2_rate                     4040633  non-null values
comp2_inv                      4251538  non-null values
comp2_rate_percent_diff        1109847  non-null values
comp3_rate                     3059273  non-null values
comp3_inv                      3292221  non-null values
comp3_rate_percent_diff        944007  non-null values
comp4_rate                     620099  non-null values
comp4_inv                      692471  non-null values
comp4_rate_percent_diff        264213  non-null values
comp5_rate                     4444294  non-null values
comp5_inv                      4720833  non-null values
comp5_rate_percent_diff        1681006  non-null values
comp6_rate                     482487  non-null values
comp6_inv                      524145  non-null values
comp6_rate_percent_diff        193312  non-null values
comp7_rate                     631077  non-null values
comp7_inv                      713175  non-null values
comp7_rate_percent_diff        277838  non-null values
comp8_rate                     3819043  non-null values
comp8_inv                      3960388  non-null values
comp8_rate_percent_diff        1225707  non-null values
click_bool                     9917530  non-null values
gross_bookings_usd             276592  non-null values
booking_bool                   9917530  non-null values
dtypes: float64(34), int64(19), object(1)None

1
您的数据类型可能没有正确定义,请使用df.info()查看。 object 应该仅用于字符串类(而不是数字)。 - Jeff
@Jeff 谢谢,我已经将 df.info() 的输出添加到问题中。我不太明白你所说的“应该只在类似字符串的数据上使用(而不是数字)”,你能解释一下吗? - piokuc
Pandas/Numpy 的版本是多少? - Jeff
我相信它们是可用的最新稳定版本。我现在要检查你的解决方案,听起来非常有前途! - piokuc
2个回答

19

这里有一个大小类似的表格,但没有对象列

In [10]: nrows = 10000000

In [11]: df = pd.concat([DataFrame(randn(int(nrows),34),columns=[ 'f%s' % i for i in range(34) ]),DataFrame(randint(0,10,size=int(nrows*19)).reshape(int(nrows),19),columns=[ 'i%s' % i for i in range(19) ])],axis=1)

In [12]: df.iloc[1000:10000,0:20] = np.nan

In [13]: df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 10000000 entries, 0 to 9999999
Data columns (total 53 columns):
f0     9991000  non-null values
f1     9991000  non-null values
f2     9991000  non-null values
f3     9991000  non-null values
f4     9991000  non-null values
f5     9991000  non-null values
f6     9991000  non-null values
f7     9991000  non-null values
f8     9991000  non-null values
f9     9991000  non-null values
f10    9991000  non-null values
f11    9991000  non-null values
f12    9991000  non-null values
f13    9991000  non-null values
f14    9991000  non-null values
f15    9991000  non-null values
f16    9991000  non-null values
f17    9991000  non-null values
f18    9991000  non-null values
f19    9991000  non-null values
f20    10000000  non-null values
f21    10000000  non-null values
f22    10000000  non-null values
f23    10000000  non-null values
f24    10000000  non-null values
f25    10000000  non-null values
f26    10000000  non-null values
f27    10000000  non-null values
f28    10000000  non-null values
f29    10000000  non-null values
f30    10000000  non-null values
f31    10000000  non-null values
f32    10000000  non-null values
f33    10000000  non-null values
i0     10000000  non-null values
i1     10000000  non-null values
i2     10000000  non-null values
i3     10000000  non-null values
i4     10000000  non-null values
i5     10000000  non-null values
i6     10000000  non-null values
i7     10000000  non-null values
i8     10000000  non-null values
i9     10000000  non-null values
i10    10000000  non-null values
i11    10000000  non-null values
i12    10000000  non-null values
i13    10000000  non-null values
i14    10000000  non-null values
i15    10000000  non-null values
i16    10000000  non-null values
i17    10000000  non-null values
i18    10000000  non-null values
dtypes: float64(34), int64(19)

时间(与您相似的机器规格)

In [14]: %timeit df.mean()
1 loops, best of 3: 21.5 s per loop

如果预先将数据转换为浮点数,您可以获得2倍的加速(mean函数也会这样做,但是以更一般的方式进行,因此速度较慢)

In [15]: %timeit df.astype('float64').mean()
1 loops, best of 3: 9.45 s per loop

你的问题在于object列。mean会尝试计算所有列,但由于object列的存在,所有数据都会被转换为不适合计算的object dtype。

最好的方法是:

 df._get_numeric_data().mean()

在较低级别上,有一个选项可以通过numeric_only来实现这一点,但由于某些原因,我们不直接支持通过顶层函数(例如mean)来实现此功能。我认为将创建一个问题来添加此参数。然而,默认情况下将是False(即不排除)。


太棒了!摆脱了我的 date_time 列,它作为对象类型加载到 pandas 中就解决了问题!现在计算平均值真的很快,就像应该的那样。非常感谢你,Jeff! - piokuc
点击这里查看如何将日期时间放入正确的数据类型。 - Jeff
@Jeff,你的链接似乎已经过时了,这个链接看起来指向了正确的部分。 为了更好地理解pandas的工作方式:如果日期列被正确解析(即类型为DatetimeIndex),那么与类型为Object的列相比,应该不会有太大的性能损失? - antiplex

0
你可以尝试这样做 -

pd.DataFrame(data.describe())

我注意到这种方法比我在 DataFrame 上使用 mean 函数更快。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接