Pandas Cythonising熊猫:内容、索引和列的ctypes

Pandas Cythonising熊猫:内容、索引和列的ctypes,pandas,cython,Pandas,Cython,我对Cython很陌生,但我已经经历了非凡的加速,只需将我的.py复制到.pyx(以及cimportCython,numpy等)并使用pyximport导入到ipython3。 许多教程从这种方法开始,下一步是为每种数据类型添加cdef声明,我可以在for循环等中为迭代器这样做。 但与大多数Pandas Cython教程或示例不同,我并没有应用函数,更多地使用切片、求和和和除法(等等)来处理数据 所以问题是:我是否可以通过声明我的数据帧只包含浮点(double),列为int,行为int,来提高代

我对Cython很陌生,但我已经经历了非凡的加速,只需将我的
.py
复制到
.pyx
(以及cimport
Cython
numpy
等)并使用
pyximport
导入到
ipython3
。 许多教程从这种方法开始,下一步是为每种数据类型添加
cdef
声明,我可以在for循环等中为迭代器这样做。 但与大多数Pandas Cython教程或示例不同,我并没有应用函数,更多地使用切片、求和和和除法(等等)来处理数据

所以问题是:我是否可以通过声明我的数据帧只包含浮点(
double
),列为
int
,行为
int
,来提高代码的运行速度

如何定义嵌入列表的类型?i、 e
[[int,int],[int]]

下面是一个为DF分区生成AIC分数的示例,很抱歉,它太冗长了:

    cimport cython
    import numpy as np
    cimport numpy as np
    import pandas as pd

    offcat = [
        "breakingPeace", 
        "damage", 
        "deception", 
        "kill", 
        "miscellaneous", 
        "royalOffences", 
        "sexual", 
        "theft", 
        "violentTheft"
        ]

    def partitionAIC(EmpFrame, part, OffenceEstimateFrame, ReturnDeathEstimate=False):
        """EmpFrame is DataFrame of ints, part is nested list of ints, OffenceEstimate frame is DF of float"""
        """partOf/block is a list of ints"""
        """ll, AIC,  is series/frame of floats"""
        ##Cython cdefs
        cdef int DFlen
        cdef int puns
        cdef int DeathPun    
        cdef int k
        cdef int pId
        cdef int punish

        DFlen = EmpFrame.shape[1]
        puns = 2
        DeathPun = 0
        PartitionModel = pd.DataFrame(index = EmpFrame.index, columns = EmpFrame.columns)

        for partOf in part:
            Grouping = [puns*x + y for x in partOf for y in list(range(0,puns))]
            PartGroupSum = EmpFrame.iloc[:,Grouping].sum(axis=1)

            for punish in range(0,puns):
                PunishGroup = [x*puns+punish for x in partOf]
                punishPunishment = ((EmpFrame.iloc[:,PunishGroup].sum(axis = 1) + 1/puns).div(PartGroupSum+1)).values[np.newaxis].T
                PartitionModel.iloc[:,PunishGroup] = punishPunishment
        PartitionModel = PartitionModel*OffenceEstimateFrame

        if ReturnDeathEstimate:
            DeathProbFrame = pd.DataFrame([[part]], index=EmpFrame.index, columns=['Partition'])
            for pId,block in enumerate(part):
                DeathProbFrame[pId] = PartitionModel.iloc[:,block[::puns]].sum(axis=1)
            DeathProbFrame = DeathProbFrame.apply(lambda row: sorted( [ [format("%6.5f"%row[idx])]+[offcat[X] for X in  x ] 
                for idx,x in enumerate(row['Partition'])],
                key=lambda x: x[0], reverse=True),axis=1)
        ll = (EmpFrame*np.log(PartitionModel.convert_objects(convert_numeric=True))).sum(axis=1)
        k = (len(part))*(puns-1)
        AIC = 2*k-2*ll

        if ReturnDeathEstimate:
            return AIC, DeathProbFrame
        else:
            return AIC

我的建议是在熊猫身上尽可能地做。这是一个标准的建议“先让它工作起来,如果它真的很重要,那么就关注性能”。因此,让我们假设您已经完成了(希望您也编写了一些测试),但是速度太慢了:

分析代码。(请参阅或在ipython中使用%prun)

prun的输出应该驱动下一步改进的位

  • pandas(使您的代码更具pandorable,这会有很大帮助)
  • numpy(不创建中间系列/数据帧,注意数据类型)
  • 赛顿(最后的手段)
  • 现在,如果这是一条关于切片的线(可能不是),那么在cython中放入微小的部分,我喜欢删除对cython函数的单个python函数调用。在这一点上,cython应该使用numpy而不是pandas,我不认为pandas不会降低到C(cython不能推断类型)


    将整个代码放入cython实际上不会有多大帮助,您只需要放入对性能敏感的特定行或函数调用。保持cython专注是享受美好时光的唯一方法

    请阅读*!在这里,这个过程(prun->cythonize->type)通过一个实际示例一步一步地介绍


    *完全公开我写的那部分文档!:)

    把我的全部代码都放到Cython中,真是帮了大忙!从隔夜跑步到20分钟!!观察CPU状态,在Python中运行时,CPU在C1+中花费了大量时间。因此,受此驱动,问题更多的是“如何获得全面加速”,而不是优化。感谢您的文档和其他工作,这是我取得成就的基础。Pandas会处理所有的单元类型并将其传递给cython吗?嗯,可能会,但我认为只需cython化一小部分代码(性能敏感位),就可以获得更有效的加速。当您使用Pandas方法时,Pandas确实会处理不同的数据类型(这些方法已经矢量化或用cython本身编写)。也就是说,作为对“如何获得整体加速而不是优化”的回应,您应该能够从优化中获得比整体加速更多的加速。