Commit 39a5acaf authored by Dr.李's avatar Dr.李

added simple settle function

parent 474f1fbb
...@@ -13,6 +13,8 @@ from libc.math cimport sqrt ...@@ -13,6 +13,8 @@ from libc.math cimport sqrt
from libc.stdlib cimport calloc from libc.stdlib cimport calloc
from libc.stdlib cimport free from libc.stdlib cimport free
np.import_array()
@cython.boundscheck(False) @cython.boundscheck(False)
@cython.wraparound(False) @cython.wraparound(False)
...@@ -29,6 +31,27 @@ cdef int max_groups(long* groups, size_t length) nogil: ...@@ -29,6 +31,27 @@ cdef int max_groups(long* groups, size_t length) nogil:
return curr_max return curr_max
@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)
@cython.initializedcheck(False)
cdef double* agg_sum(long* groups, double* x, size_t length, size_t width) nogil:
cdef long max_g = max_groups(groups, length)
cdef double* res_ptr = <double*>calloc((max_g+1)*width, sizeof(double))
cdef size_t i
cdef size_t j
cdef size_t loop_idx1
cdef size_t loop_idx2
cdef long curr
for i in range(length):
loop_idx1 = i*width
loop_idx2 = groups[i]*width
for j in range(width):
res_ptr[loop_idx2 + j] += x[loop_idx1 + j]
return res_ptr
@cython.boundscheck(False) @cython.boundscheck(False)
@cython.wraparound(False) @cython.wraparound(False)
@cython.cdivision(True) @cython.cdivision(True)
...@@ -104,7 +127,6 @@ cdef double* agg_std(long* groups, double* x, size_t length, size_t width, long ...@@ -104,7 +127,6 @@ cdef double* agg_std(long* groups, double* x, size_t length, size_t width, long
@cython.wraparound(False) @cython.wraparound(False)
@cython.initializedcheck(False) @cython.initializedcheck(False)
cpdef np.ndarray[double, ndim=2] transform(long[:] groups, double[:, :] x, str func): cpdef np.ndarray[double, ndim=2] transform(long[:] groups, double[:, :] x, str func):
cdef size_t length = x.shape[0] cdef size_t length = x.shape[0]
cdef size_t width = x.shape[1] cdef size_t width = x.shape[1]
cdef double[:, :] res_data = zeros((length, width)) cdef double[:, :] res_data = zeros((length, width))
...@@ -115,10 +137,13 @@ cpdef np.ndarray[double, ndim=2] transform(long[:] groups, double[:, :] x, str f ...@@ -115,10 +137,13 @@ cpdef np.ndarray[double, ndim=2] transform(long[:] groups, double[:, :] x, str f
cdef size_t loop_idx1 cdef size_t loop_idx1
cdef size_t loop_idx2 cdef size_t loop_idx2
if func == 'mean': if func == 'mean':
value_data_ptr = agg_mean(&groups[0], &x[0, 0], length, width) value_data_ptr = agg_mean(&groups[0], &x[0, 0], length, width)
elif func == 'std': elif func == 'std':
value_data_ptr = agg_std(&groups[0], &x[0, 0], length, width, ddof=1) value_data_ptr = agg_std(&groups[0], &x[0, 0], length, width, ddof=1)
elif func == 'sum':
value_data_ptr = agg_sum(&groups[0], &x[0, 0], length, width)
with nogil: with nogil:
for i in range(length): for i in range(length):
...@@ -126,5 +151,27 @@ cpdef np.ndarray[double, ndim=2] transform(long[:] groups, double[:, :] x, str f ...@@ -126,5 +151,27 @@ cpdef np.ndarray[double, ndim=2] transform(long[:] groups, double[:, :] x, str f
loop_idx2 = groups[i] * width loop_idx2 = groups[i] * width
for j in range(width): for j in range(width):
res_data_ptr[loop_idx1 + j] = value_data_ptr[loop_idx2 + j] res_data_ptr[loop_idx1 + j] = value_data_ptr[loop_idx2 + j]
free(value_data_ptr) free(value_data_ptr)
return asarray(res_data) return asarray(res_data)
\ No newline at end of file
@cython.boundscheck(False)
@cython.wraparound(False)
@cython.initializedcheck(False)
cpdef np.ndarray[double, ndim=2] aggregate(long[:] groups, double[:, :] x, str func):
cdef size_t length = x.shape[0]
cdef size_t width = x.shape[1]
cdef long max_g = max_groups(&groups[0], length)
cdef np.ndarray[double, ndim=2] res
cdef double* value_data_ptr
if func == 'mean':
value_data_ptr = agg_mean(&groups[0], &x[0, 0], length, width)
elif func == 'std':
value_data_ptr = agg_std(&groups[0], &x[0, 0], length, width, ddof=1)
elif func == 'sum':
value_data_ptr = agg_sum(&groups[0], &x[0, 0], length, width)
res = np.PyArray_SimpleNewFromData(2, [max_g+1, width], np.NPY_FLOAT64, value_data_ptr)
return res
\ No newline at end of file
...@@ -13,7 +13,7 @@ from numpy import arange ...@@ -13,7 +13,7 @@ from numpy import arange
def rank_build(er: np.ndarray, use_rank: int, groups: np.ndarray=None) -> np.ndarray: def rank_build(er: np.ndarray, use_rank: int, groups: np.ndarray=None) -> np.ndarray:
if er.ndim == 1 or (er.shape[0] == 1 or er.shape[1] == 1): if er.ndim == 1 or (er.shape[0] == 1 or er.shape[1] == 1):
""" fast path """ """ fast path methods for single column er"""
neg_er = -er.flatten() neg_er = -er.flatten()
length = len(neg_er) length = len(neg_er)
weights = zeros((length, 1)) weights = zeros((length, 1))
...@@ -58,16 +58,3 @@ def rank_build(er: np.ndarray, use_rank: int, groups: np.ndarray=None) -> np.nda ...@@ -58,16 +58,3 @@ def rank_build(er: np.ndarray, use_rank: int, groups: np.ndarray=None) -> np.nda
return weights return weights
if __name__ == '__main__':
import datetime as dt
x = np.random.randn(4, 2)
groups = np.random.randint(2, size=4)
start = dt.datetime.now()
for i in range(100):
weights = rank_build(x, 1)#, groups)
print(dt.datetime.now() - start)
# -*- coding: utf-8 -*-
"""
Created on 2017-4-28
@author: cheng.li
"""
\ No newline at end of file
# -*- coding: utf-8 -*-
"""
Created on 2017-4-28
@author: cheng.li
"""
import numpy as np
from alphamind.aggregate import aggregate
def simple_settle(weights: np.ndarray, ret_series: np.ndarray, groups: np.ndarray=None) -> np.ndarray:
if ret_series.ndim > 1:
ret_series = ret_series.flatten()
ret_mat = (ret_series * weights.T).T
if groups is not None:
return aggregate(groups, ret_mat, 'sum')
else:
return ret_mat.sum(axis=0)
if __name__ == '__main__':
weights = np.random.randn(200, 3)
ret_series = np.random.randn(200)
groups = np.random.randint(10, size=200)
res = simple_settle(weights, ret_series, groups)
print(res)
\ No newline at end of file
# -*- coding: utf-8 -*-
"""
Created on 2017-4-28
@author: cheng.li
"""
\ No newline at end of file
# -*- coding: utf-8 -*-
"""
Created on 2017-4-28
@author: cheng.li
"""
import unittest
import numpy as np
import pandas as pd
from alphamind.settlement.simplesettle import simple_settle
class TestSimpleSettle(unittest.TestCase):
def test_simples_settle(self):
n_samples = 3000
n_portfolio = 3
weights = np.random.randn(n_samples, n_portfolio)
ret_series = np.random.randn(n_samples)
calc_ret = simple_settle(weights, ret_series)
ret_series.shape = -1, 1
expected_ret = (weights * ret_series).sum(axis=0)
np.testing.assert_array_almost_equal(calc_ret, expected_ret)
ret_series = np.random.randn(n_samples, 1)
calc_ret = simple_settle(weights, ret_series)
expected_ret = (weights * ret_series).sum(axis=0)
np.testing.assert_array_almost_equal(calc_ret, expected_ret)
def test_simple_settle_with_group(self):
n_samples = 3000
n_portfolio = 3
n_groups = 30
weights = np.random.randn(n_samples, n_portfolio)
ret_series = np.random.randn(n_samples)
groups = np.random.randint(n_groups, size=n_samples)
calc_ret = simple_settle(weights, ret_series, groups)
ret_series.shape = -1, 1
ret_mat = weights * ret_series
expected_ret = pd.DataFrame(ret_mat).groupby(groups).sum().values
np.testing.assert_array_almost_equal(calc_ret, expected_ret)
ret_series = np.random.randn(n_samples, 1)
calc_ret = simple_settle(weights, ret_series, groups)
ret_mat = weights * ret_series
expected_ret = pd.DataFrame(ret_mat).groupby(groups).sum().values
np.testing.assert_array_almost_equal(calc_ret, expected_ret)
if __name__ == '__main__':
unittest.main()
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment