Skip to content

Commit

Permalink
Add peers structures and functions.
Browse files Browse the repository at this point in the history
- Add `DEAPeers` struct for peers of a DEA model.
- Add `DEAPeersDMU` struct for peers of a DMU in a DEA model.
- Add `ispeer` functions to test for peers.
  • Loading branch information
javierbarbero committed Jun 23, 2020
1 parent b3971d6 commit 5214fc0
Show file tree
Hide file tree
Showing 5 changed files with 395 additions and 41 deletions.
9 changes: 7 additions & 2 deletions src/DataEnvelopmentAnalysis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ module DataEnvelopmentAnalysis
# Types
AbstractDEAModel,
DEAModel,
AbstractDEAPeers, AbstractDEAPeersDMU,
DEAPeers, DEAPeersDMU,
AbstractTechnicalDEAModel, AbstractRadialDEAModel,
TechnicalDEAModel,
RadialDEAModel, AdditiveDEAModel, DirectionalDEAModel, GeneralizedDFDEAModel,
Expand All @@ -33,9 +35,11 @@ module DataEnvelopmentAnalysis
MalmquistDEAModel,
# All models
nobs, ninputs, noutputs,
# Peers
peers, ispeer,
# Technical models
dea, deaadd, deaaddweights, deaddf, deagdf,
efficiency, slacks, peers,
efficiency, slacks,
# Economic models
deacost, dearevenue, deaprofit, deaprofitability,
# Productivity models
Expand All @@ -44,7 +48,8 @@ module DataEnvelopmentAnalysis

# Include code of functions
include("model.jl")

include("peers.jl")

include("technical.jl")
include("dea.jl")
include("deaadd.jl")
Expand Down
309 changes: 309 additions & 0 deletions src/peers.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,309 @@
# This file contains types and structures for DEA peers
"""
AbstractDEAPeersDMU
An abstract type representing the DEA Peers of a DMU.
"""
abstract type AbstractDEAPeersDMU <: AbstractArray{Tuple{Tuple{Int64,String},Float64}, 1} end

"""
DEAPeersDMU
An data structure representing the DEA Peers of a DMU.
"""
struct DEAPeersDMU <: AbstractDEAPeersDMU
i::Int64
J::Vector{Int64}
V::Vector{Float64}
dmuname::String
dmunamesref::Vector{String}
end

Base.size(P::DEAPeersDMU) = (length(P.J),)

Base.IndexStyle(::Type{<:DEAPeersDMU}) = IndexLinear()

Base.getindex(P::DEAPeersDMU, i::Int) = return (P.J[i], P.dmunamesref[i]), P.V[i]

function Base.show(io::IO, x::DEAPeersDMU)
compact = get(io, :compact, false)

J = x.J
V = x.V
dmuname = x.dmuname
dmunamesref = x.dmunamesref

print(io, dmuname, ": ")

for p in x
print(io, p[1][2], " ( ", p[2], " ) ")
end

end

function Base.show(io::IO, ::MIME"text/plain", x::DEAPeersDMU)
compact = get(io, :compact, false)

J = x.J
V = x.V
dmuname = x.dmuname
dmunamesref = x.dmunamesref

print(io, "Peers of ", dmuname, ": ")
for p in x
print(io, p[1][2], " ( ", p[2], " ) ")
end

end


"""
AbstractDEAPeers
An abstract type representing a DEA Peers.
"""
abstract type AbstractDEAPeers <: AbstractArray{DEAPeersDMU, 1}end

"""
DEAPeers
An data structure representing a DEA Peers.
"""
struct DEAPeers <: AbstractDEAPeers
n::Int64
nref::Int64
lambda::SparseMatrixCSC{Float64, Int64}
I::Vector{Int64}
J::Vector{Int64}
V::Vector{Float64}
dmunames::Vector{String}
dmunamesref::Vector{String}

function DEAPeers(x::AbstractDEAModel; atol::Float64 = 1e-10, namesref::Vector{String} = Array{String}(undef, 0))
if ! isdefined(x, :lambda)
error("Model does not have info on peers.")
end

n = nobs(x)
lambda = x.lambda
nref = size(lambda, 2)
dmunames = names(x)
dmunamesref = String[]

if n != size(lambda,1)
error("Number of observation in the model and number of rows in peers matrix do not match")
end

# Remove very small numbers
droptol!(lambda, atol)

# If peers matrix is square
if length(namesref) == 0
if n == nref
dmunamesref = dmunames
else
dmunamesref = ["Ref$i" for i in 1:nref]
end
elseif length(namesref) != nref
error("Length of references names different to number of references DMUs")
else
dmunamesref = namesref
end

# Extract I, J and V vectors from SparseArray and order by I and J
I, J, V = findnz(lambda)
npeers = length(I)
IJV = [I J V]
IJV = sortslices(IJV, dims = 1, by = x -> (x[1], x[2]))

I = convert.(Int, IJV[:,1])
J = convert.(Int, IJV[:,2])
V = IJV[:,3]

new(n, nref, lambda, I, J, V, dmunames, dmunamesref)

end

end

Base.size(P::DEAPeers) = (P.n,)

Base.IndexStyle(::Type{<:DEAPeers}) = IndexLinear()

function Base.getindex(P::DEAPeers, i::Int)::DEAPeersDMU

I = P.I
J = P.J
V = P.V
dmunames = P.dmunames
dmunamesref = P.dmunamesref

DEAPeersDMU(i, J[I .== i], V[I .== i], dmunames[i], dmunamesref[unique(J[I .== i])])

end

function Base.show(io::IO, x::DEAPeers)
compact = get(io, :compact, false)

n = length(x)

println(io, "DEA Peers")

for p in x
println(io, p)
end

end

function Base.show(io::IO, ::MIME"text/plain", x::DEAPeers)
show(io, x)
end

"""
peers(model::AbstractDEAModel)
Return peers of a DEA model.
# Optional Arguments
- `atol=1e-10`: tolerance for zero values.
- `namesref`: a vector of strings with the names of the decision making units in the reference set.
# Examples
```jldoctest
julia> X = [5 13; 16 12; 16 26; 17 15; 18 14; 23 6; 25 10; 27 22; 37 14; 42 25; 5 17];
julia> Y = [12; 14; 25; 26; 8; 9; 27; 30; 31; 26; 12];
julia> deaio = dea(X, Y);
julia> peers(deaio)
DEA Peers
1: 1 ( 1.0 )
2: 4 ( 0.424978317432784 ) 7 ( 0.10928013876843023 )
3: 1 ( 1.134321653189578 ) 4 ( 0.43800539083557943 )
4: 4 ( 1.0 )
5: 4 ( 0.25738077214231636 ) 7 ( 0.04844814534443607 )
6: 7 ( 0.3333333333333333 )
7: 7 ( 1.0 )
8: 4 ( 1.0348650979425895 ) 7 ( 0.11457435012935832 )
9: 7 ( 1.1481481481481481 )
10: 4 ( 0.49056603773584906 ) 7 ( 0.4905660377358491 )
11: 11 ( 1.0 )
```
"""
peers(model::AbstractDEAModel; atol::Float64 = 1e-10, namesref::Vector{String} = Array{String}(undef, 0)) = DEAPeers(model, atol = atol, namesref = namesref) ;


"""
ispeer(P::DEAPeers, i::Int64, j::Int64)
Return `true` if `j` is peer of decision making unit `i`.
# Examples
```jldoctest
julia> X = [5 13; 16 12; 16 26; 17 15; 18 14; 23 6; 25 10; 27 22; 37 14; 42 25; 5 17];
julia> Y = [12; 14; 25; 26; 8; 9; 27; 30; 31; 26; 12];
julia> P = peers(dea(X, Y));
julia> ispeer(P, 2, 4)
true
```
"""
function ispeer(P::DEAPeers, i::Int64, j::Int64)
return P.lambda[i, j] != 0
end

"""
ispeer(P::DEAPeers, i::String, j::String)
Return `true` if `j` is peer of decision making unit `i`.
# Examples
```jldoctest
julia> X = [5 13; 16 12; 16 26; 17 15; 18 14; 23 6; 25 10; 27 22; 37 14; 42 25; 5 17];
julia> Y = [12; 14; 25; 26; 8; 9; 27; 30; 31; 26; 12];
julia> firms = ["A"; "B"; "C"; "D"; "E"; "F"; "G"; "H"; "I"; "J"; "K"]
julia> P = peers(dea(X, Y, names = firms));
julia> ispeer(P, "B", "D")
true
```
"""
function ispeer(P::DEAPeers, i::String, j::String)
# Get corresponding id's of the names
ival = findall(x -> x == i, P.dmunames)
jval = findall(x -> x == j, P.dmunames)

if length(ival) == 0
error("Name $i does not exists")
end
if length(jval) == 0
error("Name $j does not exists")
end

if length(ival) > 1
error("Name $i is repeated. Search by name not possible.")
end
if length(jval) > 1
error("Name $j is repeated. Search by name not possible.")
end

ival = ival[1]
jval = jval[1]

return ispeer(P, ival, jval)
end

"""
ispeer(P::DEAPeersDMU, j::Int64)
Return `true` if `j` is peer.
# Examples
```jldoctest
julia> X = [5 13; 16 12; 16 26; 17 15; 18 14; 23 6; 25 10; 27 22; 37 14; 42 25; 5 17];
julia> Y = [12; 14; 25; 26; 8; 9; 27; 30; 31; 26; 12];
julia> P = peers(dea(X, Y));
julia> P2 = P[2];
julia> ispeer(P2, 4)
true
```
"""
function ispeer(p::DEAPeersDMU, j::Int64)::Bool
if j <= 0
throw(BoundsError(p, j))
end

return any(p.J .== j)
end

"""
ispeer(P::DEAPeers, j::String)
Return `true` if `j` is peer.
# Examples
```jldoctest
julia> X = [5 13; 16 12; 16 26; 17 15; 18 14; 23 6; 25 10; 27 22; 37 14; 42 25; 5 17];
julia> Y = [12; 14; 25; 26; 8; 9; 27; 30; 31; 26; 12];
julia> firms = ["A"; "B"; "C"; "D"; "E"; "F"; "G"; "H"; "I"; "J"; "K"]
julia> P = peers(dea(X, Y, names = firms));
julia> P2 = P[2]
julia> ispeer(P2, "D")
true
```
"""
function ispeer(p::DEAPeersDMU, j::String)::Bool
return any(p.dmunamesref .== j)
end

# CONVERT FUNCTIONS

Base.convert(::Type{Matrix}, x::DEAPeers) = convert(Matrix, x.lambda);

Base.convert(::Type{SparseMatrixCSC}, x::DEAPeers) = x.lambda;
Loading

0 comments on commit 5214fc0

Please sign in to comment.