https://github.com/cran/cccd
Raw File
Tip revision: de4ce40da7a3b119ee4d19055a910ee9a4ad2a63 authored by David J. Marchette on 08 April 2022, 11:22:29 UTC
version 1.6
Tip revision: de4ce40
cccd.R
cccd <- function(x=NULL,y=NULL,dxx=NULL,dyx=NULL,method=NULL,k=NA,algorithm='cover_tree')
{
	if(!is.null(x) && is.vector(x)){
		x <- matrix(x,nrow=1)
	}
	if(!is.null(y) && is.vector(y)){
		y <- matrix(y,nrow=1)
	}
	if(is.null(dyx) && (is.null(method) || method=='euclidean')){
	   dyx <- get.knnx(y,x,k=1,algorithm=algorithm)
		R <- dyx$nn.dist[,1]
	} else if(is.null(dyx)){
		dyx <- as.matrix(proxy::dist(y,x,method=method))
		R <- apply(dyx,2,min)
	} else {
		R <- apply(dyx,2,min)
	}
	if(is.na(k)){
		if(is.null(dxx) | is.null(dyx)){
			if(is.null(x) | is.null(y)) stop("either x,y or dxx,dyx must be given")
			dxx <- as.matrix(proxy::dist(x,method=method))
		}
		M <- matrix(as.integer(dxx<R),length(R))
		diag(M) <- 0
		g <- graph_from_adjacency_matrix(M,mode="directed")
	} else {
		if(is.null(x) || is.null(y)) stop("x and y must not be null")
		k <- min(k,nrow(y))
	   dyx <- get.knnx(y,x,k=1,algorithm=algorithm)
	   dxx <- get.knn(x,k=k,algorithm=algorithm)
		R <- dyx$nn.dist[,1]
		out <- unlist(sapply(1:nrow(x), function(i) {
						a <- which(dxx$nn.dist[i,]<R[i])
						if(length(a)==0) return(NULL)
		            rbind(rep(i, length(a)), dxx$nn.index[i,a])
					}))
		if(is.null(out)){
			g <- make_empty_graph(n=nrow(x),directed=TRUE)
		} else {
			edges <- matrix(out,nrow=2)
			g <- make_graph(edges=edges,n=nrow(x),directed=TRUE)
		}
	}
	g$R <- R
	g$layout <- x
	g$Y <- y
	g$method <- method
	class(g) <- c("cccd",class(g))
	g
}

cccd.rw <- function(x=NULL,y=NULL,dxx=NULL,dyx=NULL,method=NULL,m=1,d=2)
{
   if(is.null(dxx) | is.null(dyx)){
		if(is.null(x) | is.null(y)) stop("either x,y or dxx,dyx must be given")
      dyx <- as.matrix(proxy::dist(y,x,method=method))
      dxx <- as.matrix(proxy::dist(x,method=method))
		d <- ncol(x)
	} 
   R <- rep(0,nrow(dxx))
	nx <- nrow(dxx)
	ny <- nrow(dyx)
	for(i in 1:nx){
		o <- order(c(dxx[i,],dyx[,i]))
	   rw <- cumsum(c(rep(1/nx,nx),rep(-1/ny,ny))[o])
		r <- sort(dxx[i,])
		R[i] <- r[which.max(rw[1:nx]-m*r^d)]
	}
	M <- matrix(as.integer(dxx<R),length(R))
	diag(M) <- 0
	g <- graph_from_adjacency_matrix(M,mode="directed")
	g$R <- R
	g$layout <- x
	g$Y <- y
	g$method <- method
	class(g) <- c("cccd",class(g))
	g
}

plot.cccd <- function(x,...,
                     plot.circles=FALSE,dominate.only=FALSE,D=NULL,
							vertex.size=2,vertex.label=NA,
							vertex.color="SkyBlue2",dom.color="Blue",
                     ypch=20,
							ycex=1.5,ycol=2,
							use.circle.radii=FALSE,
							balls=FALSE,
							ball.color=gray(.8),
							square=FALSE,
							xlim,ylim)

{
	g <- x
	class(g) <- "igraph"
	if(balls) plot.circles <- TRUE
	x <- g$layout
	n <- nrow(x)
	y <- g$Y
	if(is.null(y)){
		if(missing(xlim)){
			xlim <- range(x[,1])
		}
		if(missing(ylim)){
			ylim <- range(x[,2])
		}
	}
	else {
		if(missing(xlim)){
			xlim <- range(c(x[,1],y[,1]))
		}
		if(missing(ylim)){
			ylim <- range(c(x[,2],y[,2]))
		}
	}
	if(is.null(D)) D <- dominate(g)
	col <- rep(vertex.color,n)
	col[D] <- dom.color
	vertex.color <- col
	r <- g$R
	if(use.circle.radii){
		 xlim <- range(c(xlim[2]+r,xlim[1]-r))
		 ylim <- range(c(ylim[2]+r,ylim[1]-r))
	}
	if(square){
	   xlim <- range(c(xlim,ylim))
	   ylim <- xlim
	}
	plot(g,xlim=xlim,ylim=ylim,vertex.size=vertex.size,rescale=FALSE,
	           vertex.label=vertex.label,
				  vertex.color=vertex.color,...)
	if(plot.circles){
		col <- rep(ifelse(balls,ball.color,vertex.color),n)
		if(dominate.only){
		   col[-D] <- NA
		}
		if(balls){
			draw.circle(x[,1],x[,2],r,border=vertex.color,col=col)
			plot(g,xlim=xlim,ylim=ylim,vertex.size=vertex.size,rescale=FALSE,
				  vertex.label=vertex.label,
				  vertex.color=vertex.color,add=TRUE,...)
		} else {
			draw.circle(x[,1],x[,2],r,border=col)
		}
	}
	if(!is.null(y)){
		points(y,pch=ypch,col=ycol,cex=ycex)
	}
}

cccd.classifier <- function(x,y,dom.method='greedy',proportion=1,...)
{
	if(missing(y)){
	   if(is.list(x)){
		   y <- x$y
			x <- x$x
			if(is.null(x) | is.null(y))
			   stop("must provide either x and y or a list with attributes x and y")
		}
		else
			stop("must provide either x and y or a list with attributes x and y")
	}
   Gx <- cccd(x,y,...)
	Gy <- cccd(y,x,...)
	Dx <- dominate(Gx,method=dom.method,proportion=proportion)
	Dy <- dominate(Gy,method=dom.method,proportion=proportion)
	h <- list(Rx=Gx$R[Dx],Ry=Gy$R[Dy],Cx=matrix(x[Dx,],ncol=ncol(x)),Cy=matrix(y[Dy,],ncol=ncol(y)))
	class(h) <- "cccdClassifier"
	h
}

plot.cccdClassifier <- function(x,...,xcol=1,ycol=2,xpch=20,ypch=xpch,
                                balls=FALSE,add=FALSE)
{
   data <- rbind(x$Cx,x$Cy)
	R <- c(x$Rx,x$Ry)
	cols <- c(rep(xcol,length(x$Rx)),rep(ycol,length(x$Ry)))
	pchs <- c(rep(xpch,length(x$Rx)),rep(ypch,length(x$Ry)))
	if(add){
		points(data,col=cols,pch=pchs,...)
	} else {
		plot(data,col=cols,pch=pchs,...)
	}
	if(is.character(balls) || balls){
		if(is.character(balls)){
		   if('x' %in% balls){
				draw.circle(x$Cx[,1],x$Cx[,2],x$Rx,border=cols,col=xcol)
			}
		   if('y' %in% balls){
				draw.circle(x$Cy[,1],x$Cy[,2],x$Ry,border=cols,col=ycol)
			}
			draw.circle(data[,1],data[,2],R,border=cols)
		} else {
			draw.circle(data[,1],data[,2],R,border=cols,col=cols)
		}
	} else {
		draw.circle(data[,1],data[,2],R,border=cols)
	}
}

cccd.classifier.rw <- function(x,y,m=1,d=2)
{
	if(missing(y)){
	   if(is.list(x)){
		   y <- x$y
			x <- x$x
			if(is.null(x) | is.null(y))
			   stop("must provide either x and y or a list with attributes x and y")
		}
		else
			stop("must provide either x and y or a list with attributes x and y")
	}
   Gx <- cccd.rw(x,y,m=m,d=d)
	Gy <- cccd.rw(y,x,m=m,d=d)
	Dx <- dominate(Gx)
	Dy <- dominate(Gy)
	h <- list(Rx=Gx$R[Dx],Ry=Gy$R[Dy],
	          Cx=matrix(x[Dx,],ncol=ncol(x)),Cy=matrix(y[Dy,],ncol=ncol(y)))
	class(h) <- "cccdClassifier"
	h
}

cccd.classify <- function(data,C,method=NULL)
{
	dx <- apply(t(t(as.matrix(proxy::dist(data,C$Cx,method=method)))/C$Rx),1,min)
	dy <- apply(t(t(as.matrix(proxy::dist(data,C$Cy,method=method)))/C$Ry),1,min)
	dx<dy
}

cccd.multiclass.classifier <- function(data,classes,
                                       dom.method='greedy',proportion=1,...)
{
	cls <- unique(classes)
	nc <- length(cls)
	G <- list(0)
	D <- list(0)
	C <- list(0)
	R <- list(0)
	for(i in 1:nc){
	   z <- classes==cls[i]
		x <- data[z,]
		y <- data[!z,]
		G[[i]] <- cccd(x,y,...)
		D[[i]] <- dominate(G[[i]],method=dom.method,proportion=proportion)
		C[[i]] <- matrix(x[D[[i]],],ncol=ncol(x))
		R[[i]] <- G[[i]]$R[D[[i]]]
	}
	list(G=G,D=D,C=C,R=R,classes=cls)
}

cccd.multiclass.classify <- function(data,C,method=NULL)
{
	nc <- length(C$R)
	if(is.vector(data)) data <- matrix(data,nrow=1)
	d <- matrix(0,nrow=nc,ncol=nrow(data))
	classes <- C$classes
	for(i in 1:nc){
		d[i,] <- apply(t(t(as.matrix(proxy::dist(data,C$C[[i]],method=method)))/C$R[[i]]),1,min)
	}
	z <- t(apply(d,2,function(x)x/sum(x)))
	list(probs=z,classes=classes[apply(z,1,which.min)])
}

back to top