Python Pandas缩短了目前需要约400分钟运行的大型数据集的计算时间

0_fazistinho_

我正在尝试提高我每天需要构建的DataFrame的性能,我想知道是否有人有一些想法。我在下面创建一个简化的示例:

首先,我有一个dictDataFrame“这样的。这是时间序列数据,因此每天更新。

import pandas as pd
import numpy as np
import datetime as dt
from scipy import stats

dates = [dt.datetime.today().date() - dt.timedelta(days=x) for x in range(2000)]

m_list = [str(i) + 'm' for i in range(0, 15)]
names = [i + j  for i in m_list for j in m_list]

keys = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']
values = [pd.DataFrame([np.random.rand(225) for x in range(0, 2000)], index=dates, columns=names) for i in range(0, 10)]

df_dict = dict(zip(keys, values))    #this is my time series data

接下来,我有三个列表:

#I will build a dict of DataFrames calc attributes for these combos for each df in dict_df above
combos = ['{}/{}'.format(*np.random.choice(names, 2)) for i in range(750)] + ['{}/{}/{}'.format(*np.random.choice(names, 3)) for i in range(1500)]

periods = [20, 60, 100, 200, 500, 1000, 2000]   #num of datapoints to use from time series
benchmarks = np.random.choice(combos, 25)       #benchmarks to compare combos to

然后在这里构建所需的DataFrame:

def calc_beta (a_series, b_series) :

    covariance = np.cov (a_series, b_series)     
    beta = covariance[0, 1] / covariance[1, 1]    
    
    return beta

data_dict = {}

for i in list(df_dict.keys()) :
    
    attr_list = []
    
    df = df_dict[i]
    
    for c in combos :
        
        c_split = c.split('/')
        combo_list = []
        for cs in c_split :
            _list = [int(x) for x in list(filter(None, cs.split('m')))]
            combo_list.append(_list)
        if len(combo_list) == 2 :
            combo_list.append([np.nan, np.nan])
        
        c1a, c1b, c2a, c2b, c3a, c3b = [item for subl in combo_list for item in subl]
        
        if len(c_split) == 2 :
            l1, l2 = c_split
            _series = df[l1] - df[l2]
            
        if len(c_split) == 3 :
            l1, l2, l3 = c_split
            _series = df[l1] - df[l2] - df[l3]
        
        attr = {
            
            'name' : c,
            'a' : c1a,
            'b' : c1b,
            'c' : c2a,
            'd' : c2b,
            'e' : c3a,
            'f' : c3b,
            'series' : _series,
            'last' : _series[-1]
        }
        
        for p in periods :
            _str = str(p)
            p_series = _series[-p:]
            
            attr['quantile' + _str] = stats.percentileofscore(p_series, attr['last'])
            attr['z_score' + _str] = stats.zscore(p_series)[-1]
            attr['std' + _str] = np.std(p_series)            
            attr['range' + _str] = max(p_series) - min(p_series)
            attr['last_range' + _str] = attr['last'] / attr['range' + _str]
            attr['last_std' + _str] = attr['last'] / attr['std' + _str]        
            
            if p > 100 :
                attr['5d_autocorr' + _str] = p_series.autocorr(-5)
            else :
                attr['5d_autocorr' + _str] = np.nan
                
            for b in benchmarks :
                b_split = b.split('/')
                
                if len(b_split) == 1 :
                    b_series = df[b_split[0]]
                    
                elif len(b_split) == 2 :                    
                    b_series = df[b_split[0]] - df[b_split[1]]  
                
                elif len(b_split) == 3 :                    
                    b_series = df[b_split[0]] - df[b_split[1]] - df[b_split[2]]  
                
                b_series = b_series[-p:]
                
                corr_value = p_series.corr(b_series)
                
                beta_value = calc_beta (p_series, b_series)
                
                corr_ticker = '{}_corr{}'.format(b, _str)
                beta_ticker = '{}_beta{}'.format(b, _str)
                
                attr[corr_ticker] = corr_value    
                attr[beta_ticker] = corr_value    
        
                if p > 500 :
                    attr[b + '_20rolling_corr_mean' + _str] = p_series.rolling(20).corr(b_series).mean()

                    df1 = pd.DataFrame({c : p_series, b : b_series})

                    attr[b + '_20d_rolling_beta_mean' + _str] =  df1.rolling(20) \
                                                                    .cov(df1 , pairwise=True) \
                                                                    .drop([c], axis=1) \
                                                                    .unstack(1) \
                                                                    .droplevel(0, axis=1) \
                                                                    .apply(lambda row: row[c] / row[b], axis=1) \
                                                                    .mean()
        
        attr_list.append(attr)
    
    data_dict[i] = pd.DataFrame(attr_list)

这是实际数据的一般示例,但是它几乎完全复制了我要执行的操作,每种类型的计算,尽管我减少了数量以简化操作。

最后一部分在Dict中每个DataFrame花费大约40分钟,即此数据集总共花费400分钟。

过去我没有使用大型数据集,据我了解,我需要最小化我拥有的For循环和Apply函数,但是我还应该做什么?感谢任何输入。

谢谢

乔纳森·莱昂

所以,我去了一个黑暗的地方,找出一些可以在这里提供帮助的方法:)

长而短的是脚本结尾处的两个函数,其中p> 500会杀死您。当p <500时,我可以获得一些性能提升,我将在后面详细介绍。

我不是从本质上通过合并和填充数据框来进行迭代,而是采用了从具有所有组合(在上面的示例中为2500行)的数据框开始的方法。然后在右侧工作,并在可能的地方进行矢量化处理。我认为这里有很多改进,但是我无法使其达到预期的效果,因此也许还有其他方面可以有所帮助。

这是我最终得到的代码。从您在问题中输入的内容开始。

import pandas as pd
import numpy as np
import datetime as dt
from scipy import stats
import time

def calc_beta (a_series, b_series) :
    covariance = np.cov (a_series, b_series)
    beta = covariance[0, 1] / covariance[1, 1]
    return beta

dates = [dt.datetime.today().date() - dt.timedelta(days=x) for x in range(2000)]

m_list = [str(i) + 'm' for i in range(0, 15)]
names = [i + j  for i in m_list for j in m_list]

#keys = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']
keys = ['A']
values = [pd.DataFrame([np.random.rand(225) for x in range(0, 2000)], index=dates, columns=names) for i in range(0, 10)]

df_dict = dict(zip(keys, values))

combos = ['{}/{}'.format(*np.random.choice(names, 2)) for i in range(750)] + ['{}/{}/{}'.format(*np.random.choice(names, 3)) for i in range(1500)]

#periods = [20, 60, 100, 200, 500, 1000, 2000]   #num of datapoints to use from time series
periods = [20]   #num of datapoints to use from time series
benchmarks = np.random.choice(combos, 25)       #benchmarks to compare combos to

data_dict = {}

for i in list(df_dict.keys()):
    df = df_dict[i]
    mydf =  pd.DataFrame(combos, columns=['name'])
    mydf[['a','b','c','d','e','f']]=mydf.name.str.replace('/', '').str.replace('m', ',').str[0:-1].str.split(',', expand=True)

    def get_series(a):
        if len(a) == 2 :
            l1, l2 = a
            s = df[l1] - df[l2]
            return s.tolist()
        else:
            l1, l2, l3 = a
            s = df[l1] - df[l2] - df[l3]
            return s.tolist()

    mydf['series'] = mydf['name'].apply(lambda x: get_series(x.split('/')))
    mydf['last'] = mydf['series'].str[-1]

    for p in periods:
        _str = str(p)

        mydf['quantile' + _str] =  mydf.apply(lambda x: stats.percentileofscore(x['series'][-p:], x['last']), axis=1)
        mydf['z_score' + _str] = mydf.apply(lambda x: stats.zscore(x['series'][-p:])[-1], axis=1)
        mydf['std' + _str] = mydf.apply(lambda x: np.std(x['series'][-p:]), axis=1)
        mydf['range' + _str] = mydf.apply(lambda x: max(x['series'][-p:]) - min(x['series'][-p:]), axis=1)
        mydf['last_range' + _str] = mydf['last'] / mydf['range' + _str]
        mydf['last_std' + _str] = mydf['last'] / mydf['std' + _str]

        if p > 100 :
            mydf['5d_autocorr' + _str] = mydf.apply(lambda x: pd.Series(x['series'][-p:]).autocorr(-5), axis=1)
        else :
            mydf['5d_autocorr' + _str] = np.nan

        def get_series(a):
            if len(a) == 1 :
                b = df[a[0]]
                return b.tolist()
            elif len(a) == 2 :
                b = df[a[0]] - df[a[1]]
                return b.tolist()
            else:
                b = df[a[0]] - df[a[1]] - df[a[2]]
                return b.tolist()

        for b in benchmarks:
            corr_ticker = '{}_corr{}'.format(b, _str)
            beta_ticker = '{}_beta{}'.format(b, _str)

            b_series = get_series(b.split('/'))[-p:]

            mydf[corr_ticker] = mydf.apply(lambda x: stats.pearsonr(np.array(x['series'][-p:]), np.array(b_series))[0], axis=1)
            mydf[beta_ticker] = mydf.apply(lambda x: calc_beta(np.array(x['series'][-p:]), np.array(b_series)), axis=1)

            if p > 500 :
                mydf[b + '_20rolling_corr_mean' + _str] = mydf.apply(lambda x: pd.Series(x['series'][-p:]).rolling(20).corr(pd.Series(b_series)).mean(), axis=1)
                mydf[b + '_20d_rolling_beta_mean' + _str] =  mydf.apply(lambda x: pd.DataFrame({x['name']: pd.Series(x['series'][-p:]), b : pd.Series(b_series)}).rolling(20) \
                                                                .cov(pd.DataFrame({x['name']: pd.Series(x['series'][-p:]), b : pd.Series(b_series)}) , pairwise=True) \
                                                                .drop([x['name']], axis=1) \
                                                                .unstack(1) \
                                                                .droplevel(0, axis=1) \
                                                                .apply(lambda row: row[x['name']] / row[b], axis=1) \
                                                                .mean(), axis=1)

    data_dict[i] = mydf

我只运行了一组“ A”并更改了时间段。在保持“ A”不变并更改周期的情况下,我得到了如下所示的性能提升。在周期= 400时,我仍然可以获得60%的性能提升。

A 20
Original: Total Time 25.74614143371582
Revised: Total Time 7.026344299316406

A 200
Original: Total Time 25.56810474395752
Revised: Total Time 10.015231847763062

A 400
Original: Total Time 28.221587419509888
Revised: Total Time 11.064109802246094

转到期间501,您的原始代码花费了1121.6251230239868秒。我的差不多。从400到501会增加两个功能的大量时间(每个基准重复一次)。

如果需要这些功能并且必须在分析时进行计算,则应将时间花在这两个功能上。我发现使用pandas系列速度很慢,并且您会注意到我在一次实例中使用scipy模块进行关联,因为这样做值得。如果您可以直接将numpy或scipy模块用于最后两个功能,那么您也会从中看到收益。

另一个要看的地方是我正在使用lambda函数的地方。这仍然像使用for循环一样逐行进行。我正在保存期间序列,因此可以使用以下计算:

def get_series(a):
    if len(a) == 2 :
        l1, l2 = a
        s = df[l1] - df[l2]
        return s.tolist()
    else:
        l1, l2, l3 = a
        s = df[l1] - df[l2] - df[l3]
        return s.tolist()

mydf['series'] = mydf['name'].apply(lambda x: get_series(x.split('/')))

该系列由列表组成,并传递给lambda函数。我希望找到一种通过同时计算所有行来向量化的方法,但是某些函数需要序列,而某些函数则使用列表,因此我可以弄清楚。这是一个例子:

mydf['quantile' + _str] =  mydf.apply(lambda x: stats.percentileofscore(x['series'][-p:], x['last']), axis=1)

如果您能弄清楚如何对其进行矢量化处理,然后将其应用于p> 500的那些函数,将会发现一些节省。

最后,您的代码还是我的代码,真正的问题是后两个功能。其他所有东西都较小,但确实是节省的,并且加起来,但重新思考最后一块可以节省您的时间。

另一个选择是多进程或将其分解到多台计算机上

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

创建五分钟的时间块(Pandas / Python)

来自分类Dev

如何使用不完整的数据集创建5分钟间隔的日期时间索引(Python)

来自分类Dev

如何使用不完整的数据集创建5分钟间隔的日期时间索引(Python)

来自分类Dev

Python Pandas DataFrame缩短了从十六进制字符串到整数的转换时间

来自分类Dev

从python pandas中的15分钟间隔数据中提取每小时数据

来自分类Dev

在python中生成15分钟的时间间隔数组

来自分类Dev

VSCODE中的Python处理时间超过30分钟

来自分类Dev

如何在Python的数据框中将日期时间舍入为十分钟日期时间

来自分类Dev

Python Pandas工作日范围bdate_range不需要1分钟的频率吗?

来自分类Dev

新的Windows 10安装在会话开始前阶段需要约20分钟的时间

来自分类Dev

使用 Pandas Python 3 从 csv 中提前一分钟合并时间帧值

来自分类Dev

使用matplotlib / pandas / python,我无法将数据可视化为每30分钟和每天的值

来自分类Dev

Python熊猫-根据数据间隔的长度,平均测量10分钟,得出15分钟平均值和60分钟平均值

来自分类Dev

Python熊猫-根据数据间隔的长度,平均测量10分钟,平均测量15分钟和平均测量60分钟

来自分类常见问题

Python密码警报五分钟

来自分类Dev

Python密码警报五分钟

来自分类Dev

我的用于获取给定网站IP地址的python代码需要3分钟以上的时间才能获取结果。任何可能的原因?

来自分类Dev

如何在Python中将1分钟的开-高-低-关数据转换为另一个时间范围(fx:5分钟1小时)?

来自分类Dev

Python熊猫在15分钟内计算平均价格

来自分类Dev

Python(日期时间)时区转换关闭了4分钟

来自分类Dev

如何获得30分钟的时间段python2.7

来自分类Dev

Python For循环列表,每5分钟运行一次

来自分类Dev

每隔5分钟在与系统时钟同步的python中运行函数的最佳方法是什么?

来自分类Dev

每隔5分钟使用cron无法运行python脚本

来自分类Dev

Python Matplotlib缩短了回归线

来自分类Dev

Python熊猫每天从熊猫数据框索引中删除第一分钟

来自分类Dev

如果计算机正常运行时间大于5分钟,则需要帮助进行bash检查

来自分类Dev

使用频率为1分钟的Python在时间序列中丢弃具有Nan值的任何一天

来自分类Dev

每隔30分钟在远程Ubuntu服务器上运行我的python3程序

Related 相关文章

  1. 1

    创建五分钟的时间块(Pandas / Python)

  2. 2

    如何使用不完整的数据集创建5分钟间隔的日期时间索引(Python)

  3. 3

    如何使用不完整的数据集创建5分钟间隔的日期时间索引(Python)

  4. 4

    Python Pandas DataFrame缩短了从十六进制字符串到整数的转换时间

  5. 5

    从python pandas中的15分钟间隔数据中提取每小时数据

  6. 6

    在python中生成15分钟的时间间隔数组

  7. 7

    VSCODE中的Python处理时间超过30分钟

  8. 8

    如何在Python的数据框中将日期时间舍入为十分钟日期时间

  9. 9

    Python Pandas工作日范围bdate_range不需要1分钟的频率吗?

  10. 10

    新的Windows 10安装在会话开始前阶段需要约20分钟的时间

  11. 11

    使用 Pandas Python 3 从 csv 中提前一分钟合并时间帧值

  12. 12

    使用matplotlib / pandas / python,我无法将数据可视化为每30分钟和每天的值

  13. 13

    Python熊猫-根据数据间隔的长度,平均测量10分钟,得出15分钟平均值和60分钟平均值

  14. 14

    Python熊猫-根据数据间隔的长度,平均测量10分钟,平均测量15分钟和平均测量60分钟

  15. 15

    Python密码警报五分钟

  16. 16

    Python密码警报五分钟

  17. 17

    我的用于获取给定网站IP地址的python代码需要3分钟以上的时间才能获取结果。任何可能的原因?

  18. 18

    如何在Python中将1分钟的开-高-低-关数据转换为另一个时间范围(fx:5分钟1小时)?

  19. 19

    Python熊猫在15分钟内计算平均价格

  20. 20

    Python(日期时间)时区转换关闭了4分钟

  21. 21

    如何获得30分钟的时间段python2.7

  22. 22

    Python For循环列表,每5分钟运行一次

  23. 23

    每隔5分钟在与系统时钟同步的python中运行函数的最佳方法是什么?

  24. 24

    每隔5分钟使用cron无法运行python脚本

  25. 25

    Python Matplotlib缩短了回归线

  26. 26

    Python熊猫每天从熊猫数据框索引中删除第一分钟

  27. 27

    如果计算机正常运行时间大于5分钟,则需要帮助进行bash检查

  28. 28

    使用频率为1分钟的Python在时间序列中丢弃具有Nan值的任何一天

  29. 29

    每隔30分钟在远程Ubuntu服务器上运行我的python3程序

热门标签

归档