diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index e3462c7..0000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,22 +0,0 @@ -image: julia:1.0 # image comes from Docker hub - -before_script: - - apt-get -qq update; apt-get -y install git - - julia --project=@. -e "import Pkg; Pkg.build()" - -default: - script: - - julia --project=@. -e "import Pkg; Pkg.test(; coverage = true)" - - julia --project=test/coverage -e 'import Pkg; Pkg.instantiate()' - - julia --project=test/coverage test/coverage/coverage-summary.jl -pages: - stage: deploy -# script: -# - julia --project=docs -e 'using Pkg; Pkg.instantiate(); Pkg.develop(PackageSpec(path=pwd()))' -# - julia --project=docs --color=yes docs/make.jl -# - mv docs/build public # move to the directory picked up by Gitlab pages - artifacts: - paths: - - public - only: - - master diff --git a/.travis.yml b/.travis.yml index 58135dc..b992746 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,11 +6,7 @@ os: julia: - 1.0 - - 1.1 - - 1.2 - - 1.3 - - 1.4 - - 1.5 + - 1 branches: only: @@ -32,9 +28,6 @@ jobs: allow_failures: - os: - windows - - julia: - - 1.4 - - 1.5 include: - stage: "Documentation" julia: 1.0 diff --git a/Project.toml b/Project.toml index e3bd538..fd62437 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ authors = ["Vladimir Arnautov (mail@pharmcat.net)"] name = "ClinicalTrialUtilities" uuid = "535c2557-d7d0-564d-8ff9-4ae146c18cfe" -version = "0.3.2" +version = "0.4.0" [deps] Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" @@ -31,4 +31,4 @@ SpecialFunctions = "0.8, 0.9, 0.10, 1" Roots = "0.7, 0.8, 1" RecipesBase = "0.7, 0.8, 1" Reexport = "0.1, 0.2" -DataFrames = "0.19, 0.20" +DataFrames = "0.19, 0.20, 0.21, 0.22" diff --git a/README.md b/README.md index 810739a..e3ff967 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,10 @@ Clinical trial related calculation: descriptive statistics, power and sample size calculation, power simulations, confidence interval, pharmacokinetics/pharmacodynamics parameters calculation. This program comes with absolutely no warranty. No liability is accepted for any loss and risk to public health resulting from use of this software. -[![Build Status](https://travis-ci.com/PharmCat/ClinicalTrialUtilities.jl.svg?branch=master)](https://travis-ci.com/PharmCat/ClinicalTrialUtilities.jl) -[![Build status](https://ci.appveyor.com/api/projects/status/35f8b5vq259sbssg?svg=true)](https://ci.appveyor.com/project/PharmCat/clinicaltrialutilities-jl) +![Tier 1](https://github.com/PharmCat/ClinicalTrialUtilities.jl/workflows/Tier%201/badge.svg) + [![codecov](https://codecov.io/gh/PharmCat/ClinicalTrialUtilities.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/PharmCat/ClinicalTrialUtilities.jl) -[![Coverage Status](https://coveralls.io/repos/github/PharmCat/ClinicalTrialUtilities.jl/badge.svg?branch=master)](https://coveralls.io/github/PharmCat/ClinicalTrialUtilities.jl?branch=master) + [![Latest docs](https://img.shields.io/badge/docs-latest-blue.svg)](https://pharmcat.github.io/ClinicalTrialUtilities.jl/dev/) ## Description diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index fec8c22..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,35 +0,0 @@ -environment: - matrix: - - julia_version: 1 - - julia_version: 1.1 - -platform: - - x86 # 32-bit - - x64 # 64-bit - -# Uncomment the following lines to allow failures on nightly julia -# (tests will run but not make your overall status red) -# matrix: -# allow_failures: -# - julia_version: nightly - -branches: - only: - - master - -notifications: - - provider: Email - on_build_success: false - on_build_failure: false - on_build_status_changed: false - -install: - - ps: iex ((new-object net.webclient).DownloadString("https://raw.githubusercontent.com/JuliaCI/Appveyor.jl/version-1/bin/install.ps1")) - -build_script: - - echo "%JL_BUILD_SCRIPT%" - - C:\julia\bin\julia -e "%JL_BUILD_SCRIPT%" - -test_script: - - echo "%JL_TEST_SCRIPT%" - - C:\julia\bin\julia -e "%JL_TEST_SCRIPT%" diff --git a/cange.log b/cange.log index ef7e3e1..3f1c693 100644 --- a/cange.log +++ b/cange.log @@ -1,3 +1,8 @@ +v0.4.0 + + - remove DataFrames interim + - minor fix + v0.3.2 - bugfix fisher test - add show @@ -10,7 +15,7 @@ v0.3.1 - simulation crush fix - Equivalence Hypothesis alpha level fix! -v0.3.0 +v0.3.0 (removed) - #44 , #45 , #46 - update test - Move alpha from CTask to Hypothesis diff --git a/src/ClinicalTrialUtilities.jl b/src/ClinicalTrialUtilities.jl index c777017..bfa6e5b 100644 --- a/src/ClinicalTrialUtilities.jl +++ b/src/ClinicalTrialUtilities.jl @@ -21,7 +21,7 @@ using Distributions, Random, Roots, QuadGK, RecipesBase, Reexport import SpecialFunctions import Base: show, findfirst, getproperty, showerror, getindex, length, in, iterate, eltype, deleteat!, findall import StatsBase.confint -import DataFrames: DataFrame, DataFrames, names!, unstack, deleterows!, rename!, AbstractDataFrame +import DataFrames: DataFrame, DataFrames, unstack try methods(SpecialFunctions.logabsgamma) @@ -30,15 +30,6 @@ catch global lgamma(x) = SpecialFunctions.lgamma(x) end -#= -try - if collect(methods(DataFrames.delete!, (AbstractDataFrame, Any)))[1].file == Symbol("deprecated.jl") - DataFrames.delete!(df::AbstractDataFrame, inds) = deleterows!(df, inds) - end -catch -end -=# - const ZDIST = Normal() const LOG2 = log(2) const PI2 = π * 2.0 diff --git a/src/ci.jl b/src/ci.jl index a7fc75d..0006692 100644 --- a/src/ci.jl +++ b/src/ci.jl @@ -849,17 +849,17 @@ end # metafor: Meta-Analysis Package for R - Wolfgang Viechtbauer """ - diffcmhci(data::DataFrame; a = :a, b = :b, c = :c, d = :d, + diffcmhci(data; a = :a, b = :b, c = :c, d = :d, alpha = 0.05, method = :default)::ConfInt Cochran–Mantel–Haenszel confidence intervals for proportion difference. -**data**- dataframe with 4 columns, each line represent 2X2 table +**data**- data with 4 columns, each line represent 2X2 table -**a** **b** **c** **d** - dataframe table names (number of subjects in 2X2 table): +**a** **b** **c** **d** - data table names (number of subjects in 2X2 table): """ - function diffcmhci(data::DataFrame; a = :a, b = :b, c = :c, d = :d, alpha = 0.05, method = :default)::ConfInt + function diffcmhci(data; a = :a, b = :b, c = :c, d = :d, alpha = 0.05, method = :default)::ConfInt return diffcmhci(data[:, a], data[:, b], data[:, c], data[:, d]; alpha = alpha, method = method) #= n1 = data[:, a] + data[:, b] @@ -909,12 +909,12 @@ Cochran–Mantel–Haenszel confidence intervals for proportion difference. end """ - orcmhci(data::DataFrame; a = :a, b = :b, c = :c, d = :d, + orcmhci(data; a = :a, b = :b, c = :c, d = :d, alpha = 0.05, logscale = false)::ConfInt Cochran–Mantel–Haenszel confidence intervals for odd ratio. """ - function orcmhci(data::DataFrame; a = :a, b = :b, c = :c, d = :d, alpha = 0.05, logscale = false)::ConfInt + function orcmhci(data; a = :a, b = :b, c = :c, d = :d, alpha = 0.05, logscale = false)::ConfInt return orcmhci(data[:, a], data[:, b], data[:, c], data[:, d]; alpha = alpha, logscale = logscale) #= N = data[:, a] + data[:, b] + data[:, c] + data[:, d] @@ -949,12 +949,12 @@ Cochran–Mantel–Haenszel confidence intervals for proportion difference. if logscale return ConfInt(estimate - z*se, estimate + z*se, estimate, alpha) else return ConfInt(exp(estimate - z*se), exp(estimate + z*se), exp(estimate), alpha) end end """ - rrcmhci(data::DataFrame; a = :a, b = :b, c = :c, d = :d, + rrcmhci(data; a = :a, b = :b, c = :c, d = :d, alpha = 0.05, logscale = false)::ConfInt Cochran–Mantel–Haenszel confidence intervals for risk ratio. """ - function rrcmhci(data::DataFrame; a = :a, b = :b, c = :c, d = :d, alpha = 0.05, logscale = false)::ConfInt + function rrcmhci(data; a = :a, b = :b, c = :c, d = :d, alpha = 0.05, logscale = false)::ConfInt return rrcmhci(data[:, a], data[:, b], data[:, c], data[:, d]; alpha = alpha, logscale = logscale) #= n1 = data[:, a] + data[:, b] diff --git a/src/dataset.jl b/src/dataset.jl index 1ed538b..006ca5d 100644 --- a/src/dataset.jl +++ b/src/dataset.jl @@ -79,3 +79,15 @@ function Base.deleteat!(a::DataSet{T}, inds::Dict) where T deleteat!(a.data, findall(a, inds)) return a end + +################################################################################ +#= +function Tables.istable(table::DataSet) +end + +function Tables.rows(table::DataSet) +end + +function Tables.columns(table::DataSet) +end +=# diff --git a/src/deprecated.jl b/src/deprecated.jl index 9d84a73..3398951 100644 --- a/src/deprecated.jl +++ b/src/deprecated.jl @@ -1,5 +1,44 @@ #deprecated +#DEPRECATED + +""" + DataFrames.DataFrame(data::DataSet{PKPDProfile}; unst = false, us = false) + +Make datafrafe from PK/PD DataSet. + +unst | us - unstack data; +""" +function DataFrames.DataFrame(data::DataSet{T}; unst = false, us = false) where T + d = DataFrame(id = Int[], sortvar = Symbol[], sortval = Any[]) + for i = 1:length(data) + if length(data[i].sort) > 0 + for s in data[i].sort + push!(d, [i, s[1], s[2]]) + end + end + end + d = unstack(d, :sortvar, :sortval)[!,2:end] + df = DataFrame() + dfn = names(d) + for i = 1:size(d,2) + df[!,dfn[i]] = Array{eltype(d[!, dfn[i]]), 1}(undef, 0) + end + df = hcat(df, DataFrame(param = Any[], value = Real[])) + for i = 1:size(d,1) + a = Array{Any,1}(undef, size(d,2)) + copyto!(a, collect(d[i,:])) + for p in data[i].result + r = append!(copy(a), collect(p)) + push!(df, r) + end + end + if unst || us + return unstack(df, names(df)[end-1], names(df)[end]) + else + return df + end +end #= function ncarule!(data::DataFrame, conc::Symbol, time::Symbol, rule::LimitRule) diff --git a/src/descriptives.jl b/src/descriptives.jl index ea5995c..bc39f52 100644 --- a/src/descriptives.jl +++ b/src/descriptives.jl @@ -114,7 +114,7 @@ function Base.show(io::IO, obj::DataSet{Descriptive}) end end """ - descriptive(data::DataFrame; + descriptive(data; sort::Union{Symbol, Array{T,1}} = Array{Symbol,1}(undef,0), vars = [], stats::Union{Symbol, Array{T,1}, Tuple{Vararg{Symbol}}} = :default)::DataSet{Descriptive} where T <: Union{Symbol, String} @@ -125,7 +125,7 @@ Descriptive statistics. - ``vars`` variabels - ``stats`` statistics """ -function descriptive(data::DataFrame; +function descriptive(data; sort::Union{Symbol, Array{T,1}} = Array{Symbol,1}(undef,0), vars = [], stats::Union{Symbol, Array{T,1}, Tuple{Vararg{Symbol}}} = :default)::DataSet{Descriptive} where T <: Union{Symbol, String} @@ -202,7 +202,7 @@ end """ Push in d Descriptive obj in mx vardata """ -@inline function pushvardescriptive!(d::Array{Descriptive, 1}, vars::Array{Symbol, 1}, mx::Union{DataFrame, Matrix{T}}, sortval::Union{Tuple{Vararg{Any}}, Nothing}, stats::Tuple{Vararg{Symbol}}) where T<: Real +@inline function pushvardescriptive!(d::Array{Descriptive, 1}, vars::Array{Symbol, 1}, mx, sortval::Union{Tuple{Vararg{Any}}, Nothing}, stats::Tuple{Vararg{Symbol}}) where T<: Real for v = 1:length(vars) #For each variable in list push!(d, Descriptive(vars[v], nothing, sortval, descriptive_(mx[:, v], stats))) end @@ -210,7 +210,7 @@ end """ Check if data row sortcol equal sortval """ -@inline function checksort(data::DataFrame, row::Int, sortcol::Array{Symbol, 1}, sortval::Tuple{Vararg{Any}})::Bool +@inline function checksort(data, row::Int, sortcol::Array{Symbol, 1}, sortval::Tuple{Vararg{Any}})::Bool for i = 1:length(sortcol) if data[row, sortcol[i]] != sortval[i] return false end end @@ -219,7 +219,7 @@ end """ Return matrix of filtered data (datacol) by sortcol with sortval """ -@inline function getsortedmatrix(data::DataFrame; datacol::Array{Symbol,1}, sortcol::Array{Symbol,1}, sortval::Tuple{Vararg{Any}})::Matrix{Real} +@inline function getsortedmatrix(data; datacol::Array{Symbol,1}, sortcol::Array{Symbol,1}, sortval::Tuple{Vararg{Any}})::Matrix{Real} result = Array{Real, 1}(undef, 0) for c = 1:size(data, 1) #For each line in data if checksort(data, c, sortcol, sortval) diff --git a/src/export.jl b/src/export.jl index 1b05f95..bd95ff9 100644 --- a/src/export.jl +++ b/src/export.jl @@ -1,10 +1,10 @@ """ - htmlexport(data::DataFrame; io::IO = stdout, sort = NaN, + htmlexport(data; io::IO = stdout, sort = NaN, rspan=:all, title="Title", dict::Union{Symbol, Dict} = :undef) -HTLM export for DataFrame. +HTLM export. """ - function htmlexport(data::DataFrame; io::IO = stdout, sort = NaN, rspan=:all, title="Title", dict::Union{Symbol, Dict} = :undef) + function htmlexport(data; io::IO = stdout, sort = NaN, rspan=:all, title="Title", dict::Union{Symbol, Dict} = :undef) rowlist = Array{String,1}(undef, 0) cnames = names(data) if isa(sort, Array) @@ -189,7 +189,7 @@ HTLM export for DataFrame. """ - sort!(data, tuple(sort)) + sort!(data, sort) tablematrix .= 1 for c = 1:coln s = true diff --git a/src/freque.jl b/src/freque.jl index 0d677c7..38d3837 100644 --- a/src/freque.jl +++ b/src/freque.jl @@ -69,28 +69,36 @@ struct Freque end """ - freque(data::DataFrame; vars::Symbol, alpha = 0.05)::DataFrame + freque(data; vars::Symbol, alpha = 0.05) Frequencies. """ -function freque(data::DataFrame; vars::Symbol, alpha = 0.05)::DataFrame - result = DataFrame(value = Any[], n = Int[], p = Float64[], cil = Float64[], ciu = Float64[]) +function freque(data; vars::Symbol, alpha = 0.05) list = unique(data[:, vars]) n = length(data[:, vars]) - for i in list - ne = count(x -> (x == i), data[:, vars]) + c1 = Vector{Any}(undef, n) + c2 = Vector{Int}(undef, n) + c3 = Vector{Float64}(undef, n) + c4 = Vector{Float64}(undef, n) + c5 = Vector{Float64}(undef, n) + for i = 1:length(list) + ne = count(x -> (x == list[i]), data[:, vars]) pe = ne/n ci = ClinicalTrialUtilities.propci(ne, n, alpha=alpha, method=:wald) - push!(result, [i, ne, pe, ci.lower, ci.upper]) + c1[i] = list[i] + c2[i] = ne + c3[i] = pe + c4[i] = ci.lower + c5[i] = ci.upper end - return result + return NamedTuple{(:value, :n, :p, :cil, :ciu)}((c1, c2, c3, c4, c5)) end """ - contab(data::DataFrame; row::Symbol, col::Symbol, sort = Dict())::ConTab + contab(data; row::Symbol, col::Symbol, sort = Dict())::ConTab Make contingency table. """ -function contab(data::DataFrame; row::Symbol, col::Symbol, sort = Dict())::ConTab +function contab(data; row::Symbol, col::Symbol, sort = Dict())::ConTab clist = unique(data[:, col]) rlist = unique(data[:, row]) cn = length(clist) @@ -106,26 +114,24 @@ function contab(data::DataFrame; row::Symbol, col::Symbol, sort = Dict())::ConTa return ConTab(dfs, rlist, clist, sort) end """ - contab(data::DataFrame, sort; row::Symbol, col::Symbol) + contab(data, sort; row::Symbol, col::Symbol) Make contingency tables set. """ -function contab(data::DataFrame, sort; row::Symbol, col::Symbol) +function contab(data, sort; row::Symbol, col::Symbol) slist = unique(data[:, sort]) - clist = unique(data[:, col]) - rlist = unique(data[:, row]) + #clist = unique(data[:, col]) + #rlist = unique(data[:, row]) rcv = [row, col] result = Vector{ConTab}(undef, size(slist, 1)) - tempdf = DataFrame(row = Vector{eltype(data[!, row])}(undef, 0), col = Vector{eltype(data[!, col])}(undef, 0)) - rename!(tempdf, rcv) for si = 1:size(slist, 1) - if size(tempdf, 1) > 0 deleterows!(tempdf, 1:size(tempdf, 1)) end + inds = Vector{Int}(undef, 0) for i = 1:size(data, 1) if data[i, sort] == slist[si, :] - push!(tempdf, data[i, rcv]) + push!(inds, i) end end - result[si] = contab(tempdf, row = row, col = col, sort = Dict(sort .=> collect(slist[si, :]))) + result[si] = contab(data[inds, rcv], row = row, col = col, sort = Dict(sort .=> collect(slist[si, :]))) end return DataSet(result) end @@ -142,7 +148,7 @@ end """ mcnmcontab """ -function mcnmcontab(data::DataFrame; row::Symbol, col::Symbol, sort = Dict())::McnmConTab +function mcnmcontab(data; row::Symbol, col::Symbol, sort = Dict())::McnmConTab clist = unique(data[:, col]) rlist = unique(data[:, row]) cn = length(clist) @@ -160,22 +166,18 @@ end """ mcnmcontab """ -function mcnmcontab(data::DataFrame, sort; row::Symbol, col::Symbol) +function mcnmcontab(data, sort; row::Symbol, col::Symbol) slist = unique(data[:, sort]) - clist = unique(data[:, col]) - rlist = unique(data[:, row]) rcv = [row, col] result = Vector{McnmConTab}(undef, size(slist, 1)) - tempdf = DataFrame(row = Vector{eltype(data[!, row])}(undef, 0), col = Vector{eltype(data[!, col])}(undef, 0)) - rename!(tempdf, rcv) for si = 1:size(slist, 1) - if size(tempdf, 1) > 0 deleterows!(tempdf, 1:size(tempdf, 1)) end + inds = Vector{Int}(undef, 0) for i = 1:size(data, 1) if data[i, sort] == slist[si, :] - push!(tempdf, data[i, rcv]) + push!(inds, i) end end - result[si] = mcnmcontab(tempdf, row = row, col = col, sort = Dict(sort .=> collect(slist[si, :]))) + result[si] = mcnmcontab(data[inds, rcv], row = row, col = col, sort = Dict(sort .=> collect(slist[si, :]))) end return DataSet(result) end diff --git a/src/pk.jl b/src/pk.jl index 3223cab..bbdee8f 100644 --- a/src/pk.jl +++ b/src/pk.jl @@ -79,7 +79,7 @@ mutable struct PKSubject <: AbstractSubject function PKSubject(time::Vector, conc::Vector; sort = Dict()) new(time, conc, true, ElimRange(), DoseTime(NaN, 0 * time[1]), KelData(), sort)::PKSubject end - function PKSubject(data::DataFrame; time::Symbol, conc::Symbol, timesort::Bool = false, sort = Dict()) + function PKSubject(data; time::Symbol, conc::Symbol, timesort::Bool = false, sort = Dict()) if timesort sort!(data, time) end #Check double time new(copy(data[!,time]), copy(data[!,conc]), true, ElimRange(), DoseTime(), KelData(), sort)::PKSubject @@ -292,7 +292,7 @@ end return cmax, tmax, tmaxn end #= - function ctmax(data::DataFrame, conc::Symbol, time::Symbol) + function ctmax(data, conc::Symbol, time::Symbol) return ctmax(data[!, time], data[!, conc]) end =# @@ -879,18 +879,15 @@ vol::Vector function getdatai(data, sort, cols, func; sortby = nothing) - sortlist = unique(data[:, sort]) - datai = DataFrame() - for i in cols - datai[!, i] = Vector{eltype(data[!, i])}(undef, 0) - end + sortlist = unique(data[!, sort]) for i = 1:size(sortlist, 1) - if size(datai, 1) > 0 deleterows!(datai, 1:size(datai, 1)) end + inds = Vector{Int}(undef, 0) for c = 1:size(data, 1) #For each line in data if data[c, sort] == sortlist[i,:] - push!(datai, data[c, cols]) + push!(inds, c) end end + datai = data[inds, cols] if sortby !== nothing sort!(datai, sortby) end @@ -924,67 +921,67 @@ function tryfloatparse!(x) end """ - pkimport(data::DataFrame, sort::Array, rule::LimitRule; conc::Symbol, time::Symbol) + pkimport(data, sort::Array, rule::LimitRule; conc::Symbol, time::Symbol) -Pharmacokinetics data import from DataFrame. +Pharmacokinetics data import. -- data - sourece DataFrame; +- data - sourece data; - sort - sorting columns; - rule - applied LimitRule. - conc - concentration column; - time - time column. """ -function pkimport(data::DataFrame, sort::Array, rule::LimitRule; conc::Symbol, time::Symbol)::DataSet +function pkimport(data, sort::Array, rule::LimitRule; conc::Symbol, time::Symbol)::DataSet results = Array{PKSubject, 1}(undef, 0) if !(eltype(data[!, conc]) <: Real) throw(ArgumentError("Type of concentration data not <: Real!"))end - getdatai(data, sort, [conc, time], (x, y) -> push!(results, PKSubject(copy(x[!, time]), copy(x[!, conc]), sort = Dict(sort .=> collect(y)))); sortby = time) + getdatai(data, sort, [conc, time], (x, y) -> push!(results, PKSubject(x[!, time], x[!, conc], sort = Dict(sort .=> collect(y)))); sortby = time) results = DataSet(results) applyncarule!(results, rule) return results end """ - pkimport(data::DataFrame, sort::Array; time::Symbol, conc::Symbol) + pkimport(data, sort::Array; time::Symbol, conc::Symbol) -Pharmacokinetics data import from DataFrame. +Pharmacokinetics data import. -- data - sourece DataFrame; +- data - sourece data; - sort - sorting columns. - conc - concentration column; - time - time column. """ -function pkimport(data::DataFrame, sort::Array; time::Symbol, conc::Symbol)::DataSet +function pkimport(data, sort::Array; time::Symbol, conc::Symbol)::DataSet rule = LimitRule() return pkimport(data, sort, rule; conc = conc, time = time) end """ - pkimport(data::DataFrame, sort::Array; time::Symbol, conc::Symbol) + pkimport(data, sort::Array; time::Symbol, conc::Symbol) -Pharmacokinetics data import from DataFrame for one subject. +Pharmacokinetics data import for one subject. -- data - sourece DataFrame; +- data - sourece data; - rule - applied LimitRule. - conc - concentration column; - time - time column. """ -function pkimport(data::DataFrame, rule::LimitRule; time::Symbol, conc::Symbol)::DataSet +function pkimport(data, rule::LimitRule; time::Symbol, conc::Symbol)::DataSet #rule = LimitRule() datai = ncarule!(copy(data[!,[time, conc]]), conc, time, rule) return DataSet([PKSubject(datai[!, time], datai[!, conc])]) end """ - pkimport(data::DataFrame, sort::Array; time::Symbol, conc::Symbol) + pkimport(data, sort::Array; time::Symbol, conc::Symbol) -Pharmacokinetics data import from DataFrame for one subject. +Pharmacokinetics data import for one subject. -- data - sourece DataFrame; +- data - sourece data; - conc - concentration column; - time - time column. """ -function pkimport(data::DataFrame; time::Symbol, conc::Symbol)::DataSet +function pkimport(data; time::Symbol, conc::Symbol)::DataSet datai = sort(data[!,[time, conc]], time) return DataSet([PKSubject(datai[!, time], datai[!, conc])]) end @@ -1003,12 +1000,12 @@ function pkimport(time::Vector, conc::Vector; sort = Dict())::PKSubject end #--------------------------------------------------------------------------- """ - pdimport(data::DataFrame, sort::Array; resp::Symbol, time::Symbol, + pdimport(data, sort::Array; resp::Symbol, time::Symbol, bl::Real = 0, th::Real = NaN) -Pharmacodynamics data import from DataFrame. +Pharmacodynamics data import. -- data - sourece DataFrame; +- data - sourece data; - sort - sorting columns; - resp - responce column; @@ -1016,21 +1013,21 @@ Pharmacodynamics data import from DataFrame. - bl - baseline; - th - treashold. """ -function pdimport(data::DataFrame, sort::Array; resp::Symbol, time::Symbol, bl::Real = 0, th::Real = NaN)::DataSet +function pdimport(data, sort::Array; resp::Symbol, time::Symbol, bl::Real = 0, th::Real = NaN)::DataSet №sortlist = unique(data[:, sort]) results = Array{PDSubject, 1}(undef, 0) - getdatai(data, sort, [resp, time], (x, y) -> push!(results, PDSubject(copy(x[!, time]), copy(x[!, resp]), bl, th, sort = Dict(sort .=> collect(y)))); sortby = time) + getdatai(data, sort, [resp, time], (x, y) -> push!(results, PDSubject(x[!, time], x[!, resp], bl, th, sort = Dict(sort .=> collect(y)))); sortby = time) return DataSet(results) end -function pdimport(data::DataFrame; resp::Symbol, time::Symbol, bl = 0, th = NaN) +function pdimport(data; resp::Symbol, time::Symbol, bl = 0, th = NaN) datai = sort(data[!,[time, resp]], time) return DataSet([PDSubject(datai[!, time], datai[!, resp], bl, th)]) end #------------------------------------------------------------------------------- -function upkimport(data::DataFrame, sort::Array; stime::Symbol, etime::Symbol, conc::Symbol, vol::Symbol)::DataSet +function upkimport(data, sort::Array; stime::Symbol, etime::Symbol, conc::Symbol, vol::Symbol)::DataSet results = Array{UPKSubject, 1}(undef, 0) - getdatai(data, sort, [stime, etime, conc, vol], (x, y) -> push!(results, UPKSubject(copy(x[!, stime]), copy(x[!, etime]), copy(x[!, conc]), copy(x[!, vol]); sort =Dict(sort .=> collect(y)))); sortby = stime) + getdatai(data, sort, [stime, etime, conc, vol], (x, y) -> push!(results, UPKSubject(x[!, stime], x[!, etime], x[!, conc], x[!, vol]; sort =Dict(sort .=> collect(y)))); sortby = stime) results = DataSet(results) return results end @@ -1298,44 +1295,6 @@ function keldata(data::DataSet{PKPDProfile{PKSubject}}, i::Int) return data[i].subject.keldata end -""" - DataFrames.DataFrame(data::DataSet{PKPDProfile}; unst = false, us = false) - -Make datafrafe from PK/PD DataSet. - -unst | us - unstack data; -""" -function DataFrames.DataFrame(data::DataSet{T}; unst = false, us = false) where T - d = DataFrame(id = Int[], sortvar = Symbol[], sortval = Any[]) - for i = 1:length(data) - if length(data[i].sort) > 0 - for s in data[i].sort - push!(d, [i, s[1], s[2]]) - end - end - end - d = unstack(d, :sortvar, :sortval)[!,2:end] - df = DataFrame() - dfn = names(d) - for i = 1:size(d,2) - df[!,dfn[i]] = Array{eltype(d[!, dfn[i]]), 1}(undef, 0) - end - df = hcat(df, DataFrame(param = Any[], value = Real[])) - for i = 1:size(d,1) - a = Array{Any,1}(undef, size(d,2)) - copyto!(a, collect(d[i,:])) - for p in data[i].result - r = append!(copy(a), collect(p)) - push!(df, r) - end - end - if unst || us - return unstack(df, names(df)[end-1], names(df)[end]) - else - return df - end -end - #------------------------------------------------------------------------------- # Param functions diff --git a/src/randomization.jl b/src/randomization.jl index 2a7d607..9ac4b2b 100644 --- a/src/randomization.jl +++ b/src/randomization.jl @@ -14,7 +14,7 @@ Randomization list generaton. - ``ratio`` - group ration, [1,1] means 1:1, [1,2] means 1:2, ets. ``length(ratio)`` should be equal ``group``; - ``seed`` - RNG seed. """ -function randomseq(;blocksize::Int = 4, subject = 10, group = 2, ratio = [1,1], grseq = [["A", "B"], ["B", "A"]], seed = 0) +function randomseq(;blocksize::Int = 4, subject = 10, group = 2, ratio = [1,1], seed = 0) #rng = MersenneTwister() if seed != 0 Random.seed!(seed) end @@ -33,21 +33,20 @@ function randomseq(;blocksize::Int = 4, subject = 10, group = 2, ratio = [1,1], append!(block, fill(i, Int(rm*ratio[i]))) end fbn = subject÷blocksize #block number - rand = [] #rand list + rand = Vector{Int}(undef, 0) #rand list for i = 1:fbn append!(rand, block[sample(1:blocksize, blocksize, replace=false)]) #generate and append random block end last = subject%blocksize #not full block if last != 0 - block = [] + block = Vector{Int}(undef, 0) rm = last/r #ratio multiplication for i = 1:group append!(block, fill(i, Int(rm*ratio[i]))) end append!(rand, block[sample(1:last, last, replace=false)]) end - #seqrand = hcat(grseq[rand]...) return rand end @@ -57,7 +56,7 @@ end ratio = [1,1], grseq = ["AB", "BA"], seed = 0) -Randomization table generaton. +Randomization table generaton. Return NamedTuple of vectors. - ``blocksize`` - size of block; - ``subject`` - subject number; @@ -71,12 +70,20 @@ function randomtable(;blocksize::Int = 4, subject::Int = 10, group::Int = 2, rat if length(unique(length.(grseq))) != 1 throw(ArgumentError("Unequal grseq")) end r = randomseq(;blocksize = blocksize, subject = subject, group = group, ratio = ratio, seed = seed) - seqrand = permutedims(hcat(grseq[r]...)) - seqrand = hcat(collect(1:length(r)), hcat(r, seqrand)) - df = DataFrame(seqrand) - rename!(df, [:Subject, :Group, :Sequence]) + subj = collect(1:length(r)) + seqrand = vcat(grseq[r]...) + nl = length(grseq[1]) + 3 + nm = Vector{Symbol}(undef, nl) + np = Vector{Vector}(undef, nl) + nm[1] = :Subject + nm[2] = :Group + nm[3] = :Sequence + np[1] = subj + np[2] = r + np[3] = seqrand for i=1:length(grseq[1]) - df[!, Symbol("Period_"*string(i))] = getindex.(df[!, :Sequence], i) + nm[i+3] = Symbol("Period_"*string(i)) + np[i+3] = getindex.(seqrand, i) end - return df + return NamedTuple{Tuple(nm)}(Tuple(np)) end diff --git a/src/utilities.jl b/src/utilities.jl index 68a0045..b4e0dba 100644 --- a/src/utilities.jl +++ b/src/utilities.jl @@ -92,15 +92,15 @@ function cvfromci(theta1, theta2, n; alpha = 0.05, design=:d2x2, mso=false, cvms end """ - pooledcv(data::DataFrame; cv=:cv, df=:df, alpha=0.05, returncv=true)::ConfInt + pooledcv(data; cv=:cv, df=:df, alpha=0.05, returncv=true)::ConfInt Pooled CV from multiple sources. -**data**::DataFrame - Dataframe with CV data +**data** - data with CV data -**cv**::Symbol - CV column in dataframe +**cv**::Symbol - CV column -**df**::Symbol - DF column in dataframe +**df**::Symbol - DF column **alpha** - Alpha for var/cv confidence interval. @@ -110,7 +110,7 @@ Pooled CV from multiple sources. - false - return var """ -function pooledcv(data::DataFrame; cv = :cv, df = :df, alpha::Real = 0.05, returncv::Bool = true)::ConfInt +function pooledcv(data; cv = :cv, df = :df, alpha::Real = 0.05, returncv::Bool = true)::ConfInt if isa(cv, String) cv = Symbol(cv) end if isa(df, String) df = Symbol(df) end return pooledcv(data[!, cv], data[!, df]; alpha = alpha, returncv = returncv) diff --git a/test/freque.jl b/test/freque.jl index 801a600..0853a6f 100644 --- a/test/freque.jl +++ b/test/freque.jl @@ -4,7 +4,7 @@ println(" ---------------------------------- ") ctab = ClinicalTrialUtilities.contab(df, row = :row, col = :col) @test ctab.tab == [9 8; 5 21] - frtab = ClinicalTrialUtilities.freque(df; vars=:row, alpha = 0.05) + frtab = DataFrame(ClinicalTrialUtilities.freque(df; vars=:row, alpha = 0.05)) @test frtab[1,2] == 17 @test ClinicalTrialUtilities.fisher(ClinicalTrialUtilities.ConTab([12 23; 22 33]))[2] ≈ 0.3752579856319276 diff --git a/test/test.jl b/test/test.jl index da2e160..d6dc279 100644 --- a/test/test.jl +++ b/test/test.jl @@ -225,7 +225,7 @@ println(" ---------------------------------- ") @testset "#9 Random " begin @test ClinicalTrialUtilities.randomseq(seed = 1234) == [1,2,2,1,2,1,1,2,2,1] rdf = ClinicalTrialUtilities.randomtable(seed = 1234) - @test rdf[!, :Group] == [1,2,2,1,2,1,1,2,2,1] + @test rdf[:Group] == [1,2,2,1,2,1,1,2,2,1] end