使用 Cython 定义自定义 pandas 聚合函数
Defining a custom pandas aggregation function using Cython
我在 pandas 中有一个很大的 DataFrame
,包含三列:'col1'
是字符串,'col2'
和 'col3'
是 numpy.int64
。我需要做一个 groupby
,然后使用 apply
应用自定义聚合函数,如下所示:
pd = pandas.read_csv(...)
groups = pd.groupby('col1').apply(my_custom_function)
每个组都可以看作是一个带有两个整数列 'col2'
和 'col3'
的 numpy 数组。要理解我在做什么,您可以将每一行 ('col2','col3')
视为一个时间间隔;我正在检查是否没有相交的间隔。我首先按第一列对数组进行排序,然后测试索引 i
处的第二列值是否小于 index i + 1
.
处的第一列值
第一个问题:我的想法是使用Cython 来定义自定义聚合函数。这是个好主意吗?
我在 .pyx
文件中尝试了以下定义:
cimport nump as c_np
def c_my_custom_function(my_group_df):
cdef Py_ssize_t l = len(my_group_df.index)
if l < 2:
return False
cdef c_np.int64_t[:, :] temp_array
temp_array = my_group_df[['col2','col3']].sort(columns='col2').values
cdef Py_ssize_t i
for i in range(l - 1):
if temp_array[i, 1] > temp_array[i + 1, 0]:
return True
return False
我也定义了一个纯版本Python/pandas:
def my_custom_function(my_group_df):
l = len(my_group_df.index)
if l < 2:
return False
temp_array = my_group_df[['col2', 'col3']].sort(columns='col2').values
for i in range(l - 1):
if temp_array[i, 1] > temp_array[i + 1, 0]:
return True
return False
第二个问题:我对两个版本进行了计时,两者的时间完全相同。 Cython 版本似乎没有加快任何速度。发生了什么事?
奖金问题:你有没有更好的方法来实现这个算法?
矢量 numpy
测试可以是:
np.any(temp_array[:-1,1]>temp_array[1:,0])
它是否优于 python 或 cython 迭代取决于 True
发生的位置(如果有的话)。如果 return 处于迭代的早期步骤,则迭代显然更好。 cython
版本不会有太大的优势。此外,测试步骤将比排序步骤快。
但是如果迭代通常是一路走下去,那么向量测试会比Python迭代快,也比排序快。它可能比正确编码的 cython 迭代慢。
我在 pandas 中有一个很大的 DataFrame
,包含三列:'col1'
是字符串,'col2'
和 'col3'
是 numpy.int64
。我需要做一个 groupby
,然后使用 apply
应用自定义聚合函数,如下所示:
pd = pandas.read_csv(...)
groups = pd.groupby('col1').apply(my_custom_function)
每个组都可以看作是一个带有两个整数列 'col2'
和 'col3'
的 numpy 数组。要理解我在做什么,您可以将每一行 ('col2','col3')
视为一个时间间隔;我正在检查是否没有相交的间隔。我首先按第一列对数组进行排序,然后测试索引 i
处的第二列值是否小于 index i + 1
.
第一个问题:我的想法是使用Cython 来定义自定义聚合函数。这是个好主意吗?
我在 .pyx
文件中尝试了以下定义:
cimport nump as c_np
def c_my_custom_function(my_group_df):
cdef Py_ssize_t l = len(my_group_df.index)
if l < 2:
return False
cdef c_np.int64_t[:, :] temp_array
temp_array = my_group_df[['col2','col3']].sort(columns='col2').values
cdef Py_ssize_t i
for i in range(l - 1):
if temp_array[i, 1] > temp_array[i + 1, 0]:
return True
return False
我也定义了一个纯版本Python/pandas:
def my_custom_function(my_group_df):
l = len(my_group_df.index)
if l < 2:
return False
temp_array = my_group_df[['col2', 'col3']].sort(columns='col2').values
for i in range(l - 1):
if temp_array[i, 1] > temp_array[i + 1, 0]:
return True
return False
第二个问题:我对两个版本进行了计时,两者的时间完全相同。 Cython 版本似乎没有加快任何速度。发生了什么事?
奖金问题:你有没有更好的方法来实现这个算法?
矢量 numpy
测试可以是:
np.any(temp_array[:-1,1]>temp_array[1:,0])
它是否优于 python 或 cython 迭代取决于 True
发生的位置(如果有的话)。如果 return 处于迭代的早期步骤,则迭代显然更好。 cython
版本不会有太大的优势。此外,测试步骤将比排序步骤快。
但是如果迭代通常是一路走下去,那么向量测试会比Python迭代快,也比排序快。它可能比正确编码的 cython 迭代慢。