Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ __pycache__/

# C extensions
*.so
*.dll

auto_examples

Expand Down
253 changes: 157 additions & 96 deletions depth/model/DepthEucl.py

Large diffs are not rendered by default.

54 changes: 48 additions & 6 deletions depth/model/DepthFunc.py
Original file line number Diff line number Diff line change
Expand Up @@ -493,10 +493,6 @@ def projection_based_func_depth(self, query,
Number of random projections or optimization restarts used in computing
projection-based depth.

notion
{"mahalanobis", "halfspace", "zonoid", "projection", "aprojection", "cexpchullstar", "cexpchull", "geometrical"},
Which depth will be computed.

n_refinements
For ``solver`` = ``refinedrandom`` or ``refinedgrid``, set the maximum of iteration for
computing the depth of one point.
Expand Down Expand Up @@ -545,7 +541,7 @@ def projection_based_func_depth(self, query,
If ``output_option=="final_depth_dir"`` returns:
Tuple of array_like
- Lowest Asymmetrical Projection Detph
- Lowest depth respective sirection
- Lowest depth respective direction

Notes
-----
Expand Down Expand Up @@ -592,8 +588,54 @@ def projection_based_func_depth(self, query,


if option==1:return depth_array
else:return depth_array,direction_array
else:return depth_array,direction_array

def general_func_depth(self,query,notion='halfspace', **kwargs):
"""
Compute non projection-based functional depth for query functional data with respect to a reference dataset.

This function computes depth values of functional observations (in `query`) relative to a
reference dataset (`df`) using projection-based methods such as halfspace depth.
Each function (trajectory) is represented by a sequence of multivariate values over time.

Parameters
----------
query : pandas.DataFrame
Query dataset containing functional observations whose depth will be computed
relative to `df`. Must have the same column structure as `df`.

notion
{"mahalanobis", "halfspace", "zonoid", "projection", "aprojection", "cexpchullstar", "cexpchull", "geometrical"},
Which depth will be computed.


Returns
-------
depth_array : np.ndarray of shape (n_query,)
Array of depth values, where `n_query` is the number of functional observations
(unique `case_id`s) in the `query` dataset.
The return is the lowest comuted depth regarding all explored directions in space.

Notes
-----
- If `timestamp` is of type `datetime64`, it is converted internally to seconds
relative to the global minimum timestamp (`t_min`).
- Duplicate timestamps within each `case_id` group are automatically dropped.
- Interpolation uses linear extrapolation outside the observed time range.
"""
self._check_depth(notion)
if type(query)==np.ndarray:
query=self._3Dnp_tp_pd(query,self.TSnp, self.CInp)
if query[self.timestamp_col].max()>self.t_max:
print(f"Values with {self.timestamp_col} greater the base set domain are excluded")
query.drop(query[query[self.timestamp_col]>self.t_max].index, inplace=True)
if query[self.timestamp_col].min()>self.t_min:
print(f"Values with {self.timestamp_col} smaller the base set domain are excluded")
query.drop(query[query[self.timestamp_col]<self.t_min].index, inplace=True)
queryMM=self._MinMax(query)
query_array = self._syncronise_over_time(queryMM,)
depth_array = np.empty((query_array.shape[0],), dtype = float)
pass

def _check_hyperparDepth(self,**kwargs):
n_refinements = 10
Expand Down
15 changes: 5 additions & 10 deletions depth/model/multivariate/ACA_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,18 @@
import sys, os, glob
from .import_CDLL import libACA

def ACA(X, dim = 1, sample_size = None, sample = None, notion = "projection", # Can't use halfspace with NelderMead
def ACA(X, dim = 1, sample_size = None, notion = "projection", # Can't use halfspace with NelderMead
solver = "neldermead", NRandom = 100, n_refinements = 10, sphcap_shrink = 0.5,
alpha_Dirichlet = 1.25, cooling_factor = 0.95, cap_size = 1, start = "mean",
space = "sphere", line_solver = "goldensection", bound_gc = True):

z=X.copy()

if(sample_size != None and sample == None): # Run method on a (specified) sample
if(sample_size != None): # Run method on a (specified) sample
ind = np.random.default_rng().choice(X.shape[0], size=sample_size, replace=False)
X = X[ind]
elif(sample_size == None and sample is not None):
ind = sample
X = X[sample]
elif(sample_size != None and sample is not None):
print("Can't give size of uniform sampling and your own index for sampling")
return(None)
else:
pass

# Check arguments
depth_indice = check_depth(notion)
Expand All @@ -37,8 +33,7 @@ def ACA(X, dim = 1, sample_size = None, sample = None, notion = "projection", #
try:
n, d = X.shape
except ValueError:
n = X.shape[0]
d = 1
n,d = X.shape[0],1
basis = np.eye(d, dtype=np.double)
d_aca = d
iter_aca = dim
Expand Down
9 changes: 6 additions & 3 deletions depth/model/multivariate/Aprojection.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@ def aprojection(x, data,
line_solver = "goldensection",
bound_gc = True,
CUDA=False,
device=None):
device=None,
seed=2801):

if CUDA==False:
return depth_approximation(x, data, "aprojection", solver, NRandom, option, n_refinements,
sphcap_shrink, alpha_Dirichlet, cooling_factor, cap_size, start, space, line_solver, bound_gc,)
sphcap_shrink, alpha_Dirichlet, cooling_factor, cap_size, start, space, line_solver,
bound_gc,seed=seed)
if CUDA==True:
return cudaApprox(data,x, "aprojection", solver, option,NRandom, n_refinements, sphcap_shrink,device=device)
return cudaApprox(data,x, "aprojection", solver, option,NRandom, n_refinements, sphcap_shrink,
device=device, seed=seed)


aprojection.__doc__="""
Expand Down
17 changes: 9 additions & 8 deletions depth/model/multivariate/BetaSkeleton.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@
from ctypes import *
from multiprocessing import *
import math
import sklearn.covariance as sk
# import sklearn.covariance as sk
import sys, os, glob
import platform
from .import_CDLL import libExact

def MCD_fun(data,alpha,NeedLoc=False):
cov = sk.MinCovDet(support_fraction=alpha).fit(data)
if NeedLoc:return([cov.covariance_,cov.location_])
else:return(cov.covariance_)
# def MCD_fun(data,alpha,NeedLoc=False):
# cov = sk.MinCovDet(support_fraction=alpha).fit(data)
# if NeedLoc:return([cov.covariance_,cov.location_])
# else:return(cov.covariance_)

def betaSkeleton(x, data, beta = 2, distance = "Lp", Lp_p = 2, mah_estimate = "moment", mah_parMcd = 0.75):
def betaSkeleton(x, data, beta = 2, distance = "Lp", Lp_p = 2, mah_estimate = "moment", mah_parMcd = 0.75,
covMCD=None):
points_list=data.flatten()
objects_list=x.flatten()
if (distance == "Mahalanobis"):
Expand All @@ -22,8 +23,8 @@ def betaSkeleton(x, data, beta = 2, distance = "Lp", Lp_p = 2, mah_estimate = "m
else:
if(mah_estimate == "moment"):
tmpCov = np.cov(np.transpose(data))
elif (mah_estimate == "MCD"):
tmpCov = MCD_fun(data, mah_parMcd)
elif (mah_estimate.lower() == "mcd"):
tmpCov = covMCD
else:
print("Wrong argument \"mah_estimate\", should be one of \"moment\", \"MCD\", \"none\"")

Expand Down
4 changes: 2 additions & 2 deletions depth/model/multivariate/CUDA_approximation.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
# device = torch.device("cpu")
def cudaApprox(data:torch.Tensor,x:torch.Tensor,notion:str,
solver:str,option:int,NRandom:int,n_refinements:int,sphcap_shrink:float,
step:int=10000,device="cpu")->torch.Tensor:
step:int=10000,device="cpu", seed=2801)->torch.Tensor:
"""Main function to compute approximated depth based on chosen notion
"""
torch.manual_seed(2801)
torch.manual_seed(seed)
# IMPORTANT TO REMEMBER: data is a transposed matrix, spaceDim x nSamples
if len(x.shape)==1:x=x.reshape(1,-1)
# xCUDA=torch.tensor(x,dtype=torch.float32,device=device) # transfert x to cuda
Expand Down
5 changes: 3 additions & 2 deletions depth/model/multivariate/Cexpchull.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ def cexpchull(x, data,
start = "mean",
space = "sphere",
line_solver = "goldensection",
bound_gc = True):
bound_gc = True,
seed=2801):

return depth_approximation(x, data, "cexpchull", solver, NRandom, option, n_refinements,
sphcap_shrink, alpha_Dirichlet, cooling_factor, cap_size, start, space, line_solver, bound_gc)
sphcap_shrink, alpha_Dirichlet, cooling_factor, cap_size, start, space, line_solver, bound_gc,seed)

cexpchull.__doc__="""

Expand Down
5 changes: 3 additions & 2 deletions depth/model/multivariate/Cexpchullstar.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ def cexpchullstar(x, data,
start = "mean",
space = "sphere",
line_solver = "goldensection",
bound_gc = True):
bound_gc = True,
seed=2801):

return depth_approximation(x, data, "cexpchullstar", solver, NRandom, option, n_refinements,
sphcap_shrink, alpha_Dirichlet, cooling_factor, cap_size, start, space, line_solver, bound_gc)
sphcap_shrink, alpha_Dirichlet, cooling_factor, cap_size, start, space, line_solver, bound_gc,seed)

cexpchullstar.__doc__="""

Expand Down
13 changes: 8 additions & 5 deletions depth/model/multivariate/Depth_approximation.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from math import ceil
import sys, os, glob
import platform
from .import_CDLL import libApprox
from .import_CDLL import libApprox, libExact

def depth_approximation(z,
X,
Expand All @@ -19,14 +19,16 @@ def depth_approximation(z,
start = "mean",
space = "sphere",
line_solver = "goldensection",
bound_gc = True):
bound_gc = True,
seed = 2801):

depth_indice = check_depth(notion)
check_space(space)
solver_indice = check_solver(solver, space)
start_indice = check_start(start)
line_solver_indice = check_line_solver(line_solver)
check_bound(bound_gc)


try:
n, d = X.shape
Expand Down Expand Up @@ -80,7 +82,7 @@ def depth_approximation(z,
objects=(c_double*len(objects_list))(*objects_list)
points=pointer(points)
objects=pointer(objects)

seed = pointer((c_int(seed)))

libApprox.depth_approximation(
objects,
Expand All @@ -104,14 +106,15 @@ def depth_approximation(z,
c_void_p(depths_iter.ctypes.data),
c_void_p(directions.ctypes.data),
c_void_p(directions_card.ctypes.data),
c_void_p(best_directions.ctypes.data)
c_void_p(best_directions.ctypes.data),
seed
)

if(option == 2 or option == 3 or option == 4):
for i in range(n_z):
if(np.sum(z[i]*best_directions[i]) < np.sum(z[i]*(-best_directions[i]))):
best_directions[i] = -best_directions[i]
# print(option)

depths=np.nan_to_num(depths, nan=0)
if(option == 1):
return depths
Expand Down
5 changes: 3 additions & 2 deletions depth/model/multivariate/Geometrical.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ def geometrical(x, data,
start = "mean",
space = "sphere",
line_solver = "goldensection",
bound_gc = True):
bound_gc = True,
seed=2801):

return depth_approximation(x, data, "geometrical", solver, NRandom, option, n_refinements,
sphcap_shrink, alpha_Dirichlet, cooling_factor, cap_size, start, space, line_solver, bound_gc)
sphcap_shrink, alpha_Dirichlet, cooling_factor, cap_size, start, space, line_solver, bound_gc,seed)


geometrical.__doc__="""
Expand Down
7 changes: 4 additions & 3 deletions depth/model/multivariate/Halfspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ def halfspace(x, data, exact=True, method="recursive",
line_solver = "goldensection",
bound_gc = True,
CUDA=False,
device=None):
device=None,
seed=2801):
if exact:
if (method =="recursive" or method==1):
method=1
Expand Down Expand Up @@ -56,10 +57,10 @@ def halfspace(x, data, exact=True, method="recursive",
return res
else:
if CUDA==False:return depth_approximation(x, data, "halfspace", solver, NRandom ,option, n_refinements,
sphcap_shrink, alpha_Dirichlet, cooling_factor, cap_size, start, space, line_solver, bound_gc)
sphcap_shrink, alpha_Dirichlet, cooling_factor, cap_size, start, space, line_solver, bound_gc,seed)
if CUDA==True:
return cudaApprox(data,x, "halfspace", solver=solver, option=option,NRandom=NRandom, n_refinements=n_refinements,
sphcap_shrink=sphcap_shrink,device=device)
sphcap_shrink=sphcap_shrink,device=device,seed=seed)

halfspace.__doc__="""

Expand Down
16 changes: 8 additions & 8 deletions depth/model/multivariate/L2.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import numpy as np
from ctypes import *
from multiprocessing import *
import sklearn.covariance as sk
# import sklearn.covariance as sk
import sys, os, glob
import platform

def MCD_fun(data,alpha,NeedLoc=False):
cov = sk.MinCovDet(support_fraction=alpha).fit(data)
if NeedLoc:return([cov.covariance_,cov.location_])
else:return(cov.covariance_)
# def MCD_fun(data,alpha,NeedLoc=False):
# cov = sk.MinCovDet(support_fraction=alpha).fit(data)
# if NeedLoc:return([cov.covariance_,cov.location_])
# else:return(cov.covariance_)

def L2(x, data,mah_estimate='moment',mah_parMcd=0.75):
def L2(x, data,mah_estimate='moment',mah_parMcd=0.75,covMCD=None):
points_list=data.flatten()
objects_list=x.flatten()

Expand All @@ -19,8 +19,8 @@ def L2(x, data,mah_estimate='moment',mah_parMcd=0.75):
else:
if mah_estimate=='moment':
cov=np.cov(np.transpose(data))
elif mah_estimate=='MCD':
cov=MCD_fun(data, mah_parMcd)
elif mah_estimate.lower()=='mcd':
cov=covMCD
else :
print("Wrong argument \"mah.estimate\", should be one of \"moment\", \"MCD\", \"none\"")
print("moment is used")
Expand Down
Loading
Loading