[英]Fastest way to get the mode of a pandas Series with NaN
我需要通过 object 或单个系列找到 pandas 组的模式/最常见元素,为此我有以下 function:
def get_most_common(srs):
from collections import Counter
import numpy as np
x = list(srs)
my_counter = Counter(x)
if np.nan not in my_counter.keys():
most_common_value = my_counter.most_common(1)[0][0]
else:
most_common_value = srs.mode(dropna=False).iloc[0]
return most_common_value
在平局的情况下,我不在乎选择哪一个——随机就可以了。
当没有 NaN 时, Counter
会更快,但使用 NaN 时会给出错误的结果。 pd.Series.mode
总是正确的,但是当没有 NaN 时它比Counter
慢。 这是一场赌博(没有 NaN 时速度更快,但有 NaN 时速度较慢,因为额外检查np.nan not in my_counter.keys()
)。 到目前为止,我的大型数据集的性能令人满意,可能是因为很多情况下没有 NaN。 但是有没有办法让这更快?
我觉得奇怪的是,您使用Counter
获得了更好的性能。 这是我的测试结果( n=10000
):
Using Series.mode on Series with nan: 52.41649858
Using Series.mode on Series without nan: 17.186453438
Using Counter on Series with nan: 269.33117825500005
Using Counter on Series without nan: 134.207576572
#-----------------------------------------------------#
Series.mode Counter
----------- -------------
With nan 52.42s 269.33s
Without nan 17.19s 134.21s
测试代码:
import timeit
setup = '''
import pandas as pd
from collections import Counter
def get_most_common(srs):
return srs.mode(dropna=False)[0]
def get_most_common_counter(srs):
x = list(srs)
my_counter = Counter(x)
return my_counter.most_common(1)[0][0]
df = pd.read_csv(r'large.data')
'''
print(f"""Using Series.mode on Series with nan: {timeit.timeit('get_most_common(df["has_nan"])', setup=setup, number=10000)}""")
print(f"""Using Series.mode on Series without nan: {timeit.timeit('get_most_common(df["no_nan"])', setup=setup, number=10000)}""")
print(f"""Using Counter on Series with nan: {timeit.timeit('get_most_common_counter(df["has_nan"])', setup=setup, number=10000)}""")
print(f"""Using Counter on Series without nan: {timeit.timeit('get_most_common_counter(df["no_nan"])', setup=setup, number=10000)}""")
large.data
是 2 x 50000 行DataFrame
的随机 2 位字符串,从0
到99
,其中has_nan
的mode
为nan=551
。
如果有的话,您的if np.nan not in my_counter.keys()
条件将始终被触发,因为np.nan
不在my_counter.keys()
中。 所以实际上你从来没有使用pd.Series.mode
,它总是在使用Counter
。 如另一个问题所述,由于您的pandas
object 已经在Series/DataFrame
中创建了np.nan
的副本,因此永远不会满足in
条件。 试试看:
np.nan in pd.Series([np.nan, 1, 2]).to_list()
# False
消除if/else
的全部复杂性并坚持使用一种方法。 然后比较性能。 正如您在另一个问题中提到的,pandas 方法几乎总是比任何外部模块/方法更好的方法。 如果您仍在观察其他情况,请更新您的问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.