@@ -14,9 +14,12 @@ function nomissing(data, cols::AbstractVector)
1414 true
1515end
1616
17- function functional_term (f, arg_expr... )
18- expr = Expr (:call , Symbol (f), arg_expr... )
19- eval (:(@formula 0 ~ $ expr)). rhs
17+ function functional_term (f, args... )
18+ FunctionTerm (
19+ f,
20+ term .(args),
21+ Expr (:call , Symbol (f), args... )
22+ )
2023end
2124
2225"""
@@ -336,6 +339,40 @@ function makeseq(data;
336339 map (x-> subjdict[x], getcol (data, subject))
337340end
338341
342+
343+ function models_create (be, estimator, design = " auto" )
344+ if design == " parallel"
345+ if be. logt
346+ return [FormulaTerm (term (i), term (be. formulation)) for i in be. vars]
347+ else
348+ return [FormulaTerm (functional_term (log, i), term (be. formulation)) for i in be. vars]
349+ end
350+ end
351+
352+
353+ if estimator == " glm"
354+ if be. logt
355+ return [FormulaTerm (term (i), term (be. formulation) + term (be. period) + term (be. sequence) + term (be. subject)) for i in be. vars]
356+ else
357+ return [FormulaTerm (functional_term (log, i), term (be. formulation) + term (be. period) + term (be. sequence) + term (be. subject)) for i in be. vars]
358+ end
359+ elseif estimator == " met"
360+ if be. logt
361+ return [FormulaTerm (term (i), term (be. formulation) + term (be. period) + term (be. sequence)) for i in be. vars]
362+ else
363+ return [FormulaTerm (functional_term (log, i), term (be. formulation) + term (be. period) + term (be. sequence)) for i in be. vars]
364+ end
365+ elseif estimator == " mm"
366+ if be. logt
367+ return [FormulaTerm (term (i), term (be. formulation) + term (be. period) + term (be. sequence) + functional_term (| , 1 , be. subject)) for i in be. vars]
368+ else
369+ return [FormulaTerm (functional_term (log, i), term (be. formulation) + term (be. period) + term (be. sequence) + functional_term (| , 1 , be. subject)) for i in be. vars]
370+ end
371+ else
372+ error (" Unknown estimator!" )
373+ end
374+ end
375+
339376"""
340377 estimate(be; estimator = "auto", method = "auto", supresswarn = false, alpha = 0.05)
341378
@@ -388,7 +425,7 @@ EMA: [GUIDELINE ON THE INVESTIGATION OF BIOEQUIVALENCE](https://www.ema.europa.e
388425EMA: [GUIDELINE ON THE INVESTIGATION OF BIOEQUIVALENCE, Annex I](https://www.ema.europa.eu/en/documents/other/31-annex-i-statistical-analysis-methods-compatible-ema-bioequivalence-guideline_en.pdf)
389426
390427"""
391- function estimate (be; estimator = " auto" , method = " auto" , supresswarn = false , alpha = 0.05 )
428+ function estimate (be; estimator = " auto" , method = " auto" , supresswarn = false , alpha = 0.05 , rsabe = :none , ntid = false )
392429
393430 length (be. formulations) > 2 && error (" More than 2 formulations not supported yet" )
394431 design = be. design
@@ -432,17 +469,8 @@ function estimate(be; estimator = "auto", method = "auto", supresswarn = false,
432469 if method != " P" && ! supresswarn @warn (" Method not P (parallel), for parallel simple GLM model will be used!" ) end
433470 estimator = " glm"
434471 method = " P"
435- if be. logt
436- models = [@eval @formula ($ i ~ $ (be. formulation)) for i in be. vars]
437- else
438- models = [begin
439- rfo = @eval @formula (0 ~ $ (be. formulation))
440- lhs = functional_term (log, i)
441- FormulaTerm (lhs, rfo. rhs)
442- end for i in be. vars
443- # @eval @formula(log(Term($i)) ~ $(be.formulation)) for i in be.vars
444- ]
445- end
472+
473+ models = models_create (be, estimator, design)
446474
447475 elseif design in (" 2X2" , " 2X2X2" )
448476
@@ -458,39 +486,7 @@ function estimate(be; estimator = "auto", method = "auto", supresswarn = false,
458486 end
459487 end
460488
461- if estimator == " glm"
462- if be. logt
463- models = [@eval @formula ($ i ~ $ (be. formulation) + $ (be. period) + $ (be. sequence) + $ (be. subject)) for i in be. vars]
464- else
465- models = [begin
466- rfo = @eval @formula (0 ~ $ (be. formulation) + $ (be. period) + $ (be. sequence) + $ (be. subject))
467- lhs = functional_term (log, i)
468- FormulaTerm (lhs, rfo. rhs)
469- end for i in be. vars]
470- end
471- elseif estimator == " met"
472- if be. logt
473- models = [@eval @formula ($ i ~ $ (be. formulation) + $ (be. period) + $ (be. sequence)) for i in be. vars]
474- else
475- models = [begin
476- rfo = @eval @formula (0 ~ $ (be. formulation) + $ (be. period) + $ (be. sequence))
477- lhs = functional_term (log, i)
478- FormulaTerm (lhs, rfo. rhs)
479- end for i in be. vars]
480- end
481- elseif estimator == " mm"
482- if be. logt
483- models = [@eval @formula ($ i ~ $ (be. formulation) + $ (be. period) + $ (be. sequence) + (1 | $ (be. subject) )) for i in be. vars]
484- else
485- models = [begin
486- rfo = @eval @formula (0 ~ $ (be. formulation) + $ (be. period) + $ (be. sequence) + (1 | $ (be. subject) ))
487- lhs = functional_term (log, i)
488- FormulaTerm (lhs, rfo. rhs)
489- end for i in be. vars]
490- end
491- else
492- error (" Unknown estimator!" )
493- end
489+ models = models_create (be, estimator)
494490
495491 else
496492 if ! (method in (" A" , " B" , " C" ))
@@ -513,47 +509,16 @@ function estimate(be; estimator = "auto", method = "auto", supresswarn = false,
513509 estimator = " met"
514510 end
515511
516- if estimator == " glm"
517- if be. logt
518- models = [@eval @formula ($ i ~ $ (be. formulation) + $ (be. period) + $ (be. sequence) + $ (be. subject)) for i in be. vars]
519- else
520- models = [begin
521- rfo = @eval @formula (0 ~ $ (be. formulation) + $ (be. period) + $ (be. sequence) + $ (be. subject))
522- lhs = functional_term (log, i)
523- FormulaTerm (lhs, rfo. rhs)
524- end for i in be. vars]
525- end
526- elseif estimator == " met"
527- if be. logt
528- models = [@eval @formula ($ i ~ $ (be. formulation) + $ (be. period) + $ (be. sequence)) for i in be. vars]
529- else
530- models = [begin
531- rfo = @eval @formula (0 ~ $ (be. formulation) + $ (be. period) + $ (be. sequence))
532- lhs = functional_term (log, i)
533- FormulaTerm (lhs, rfo. rhs)
534- end for i in be. vars]
535- end
536- elseif estimator == " mm"
537- if be. logt
538- models = [@eval @formula ($ i ~ $ (be. formulation) + $ (be. period) + $ (be. sequence) + (1 | $ (be. subject) )) for i in be. vars]
539- else
540- models = [begin
541- rfo = @eval @formula (0 ~ $ (be. formulation) + $ (be. period) + $ (be. sequence) + (1 | $ (be. subject) ))
542- lhs = functional_term (log, i)
543- FormulaTerm (lhs, rfo. rhs)
544- end for i in be. vars]
545-
546- end
547- else
548- error (" Unknown estimator!" )
549- end
512+ models = models_create (be, estimator)
550513 end
551514
515+ if rsabe != :none && design in (" parallel" , " 2X2" , " 2X2X2" ) && ! supresswarn @warn (" rsabe option used with unsupported design, nothing will be done!" ) end
516+
552517 # ###################################
553518 # ESTIMATION (fitting)
554519 # ###################################
555520 df = DataFrame (Parameter = String[], Metric = String[], PE = Float64[], SE = Float64[], DF = Float64[], lnLCI = Float64[], lnUCI = Float64[], GMR = Float64[], LCI = Float64[], UCI = Float64[], level = Float64[])
556- dfdict = Dict (:result => df)
521+ dfdict = Dict {Symbol, DataFrame} (:result => df)
557522 # If GLM used
558523 if estimator == " glm"
559524
@@ -585,9 +550,6 @@ function estimate(be; estimator = "auto", method = "auto", supresswarn = false,
585550 σ²,
586551 cvfromvar (σ²) * 100
587552 ))
588-
589-
590-
591553 end
592554
593555 # If Metida Used
@@ -598,14 +560,14 @@ function estimate(be; estimator = "auto", method = "auto", supresswarn = false,
598560 if method == " B"
599561
600562 results = [fit! (LMM (m, be. data;
601- random = Metida. VarEffect (@eval (Metida . @covstr ( 1 | $ ( be. subject)) ), Metida. SI),
563+ random = Metida. VarEffect (functional_term ( | , 1 , be. subject), Metida. SI),
602564 contrasts = Dict (be. formulation => DummyCoding (base = be. reference)))) for m in models]
603565
604566 elseif method == " C"
605-
567+
606568 results = [fit! (LMM (m, be. data;
607- random = Metida. VarEffect (@eval (Metida . @covstr ( $ ( be. formulation) | $ ( be. subject)) ), Metida. CSH),
608- repeated = Metida. VarEffect (@eval (Metida . @covstr ( $ ( be. formulation) | $ ( be. subject)) ), Metida. DIAG),
569+ random = Metida. VarEffect (functional_term ( | , be. formulation, be. subject), Metida. CSH),
570+ repeated = Metida. VarEffect (functional_term ( | , be. formulation, be. subject), Metida. DIAG),
609571 contrasts = Dict (be. formulation => DummyCoding (base = be. reference)))) for m in models]
610572
611573 else
@@ -686,6 +648,60 @@ function estimate(be; estimator = "auto", method = "auto", supresswarn = false,
686648
687649 end
688650
651+ if rsabe != :none && ! (design in (" parallel" , " 2X2" , " 2X2X2" ))
652+ if ! (rsabe in (:ema , :fda , :eeu )) rsabe = :unknown end
653+ cvdf = dfdict[:scaled_ci ] = DataFrame (Metric = String[], Reference = String[], σ²= Float64[], CV = Float64[], Method = String[], LCIL = Float64[], UCIL = Float64[] )
654+
655+ if be. logt
656+ cv_models = [FormulaTerm (term (i), term (be. period) + term (be. sequence) + term (be. subject)) for i in be. vars]
657+ else
658+ cv_models = [begin
659+ rfo = FormulaTerm (0 , term (be. period) + term (be. sequence) + term (be. subject))
660+ lhs = functional_term (log, i)
661+ FormulaTerm (lhs, rfo. rhs)
662+ end for i in be. vars]
663+ end
664+ cv_data = filter (be. formulation => x -> x == be. reference, be. data)
665+
666+ cv_results = [fit (LinearModel, m, cv_data; dropcollinear = true ) for m in cv_models]
667+
668+ for cvr in cv_results
669+ σ² = GLM. dispersion (cvr. model, true )
670+ s_wr = sqrt (σ²)
671+ cv_w = cvfromvar (σ²) * 100
672+
673+ if rsabe in (:ema , :eeu )
674+ lcil = cv_w > 30 ? max (69.84 , round (exp (- 0.760 * s_wr) * 100 , digits = 2 )) : 80.0
675+ ucil = cv_w > 30 ? min (143.19 , round (exp (0.760 * s_wr) * 100 , digits = 2 )) : 125.00
676+ elseif rsabe == :fda
677+ if ntid
678+ lcil = s_wr > 0.1 ? round (exp (- 0.893 * s_wr) * 100 , digits = 2 ) : 90.0
679+ ucil = s_wr > 0.1 ? round (exp (0.893 * s_wr) * 100 , digits = 2 ) : 111.11
680+ else
681+ lcil = cv_w >= 30 ? round (exp (- 0.893 * s_wr) * 100 , digits = 2 ) : 80.0
682+ ucil = cv_w >= 30 ? round (exp (0.893 * s_wr) * 100 , digits = 2 ) : 125.00
683+ end
684+ else
685+ rsabe = :unknown
686+ lcil = NaN
687+ ucil = NaN
688+ end
689+
690+ push! (cvdf, (
691+ coefnames (cvr. mf. f. lhs),
692+ string (be. reference),
693+ σ²,
694+ cv_w,
695+ string (rsabe),
696+ lcil,
697+ ucil,
698+ ))
699+ end
700+
701+ end
702+
703+
704+
689705 BEResults (be, results, dfdict, estimator, method)
690706end
691707
@@ -696,4 +712,13 @@ Returns dataframe with bioequivalence results.
696712"""
697713function result (beres:: BEResults )
698714 beres. df[:result ]
715+ end
716+
717+ """
718+ variance(beres::BEResults)
719+
720+ Returns dataframe with variance.
721+ """
722+ function variance (beres:: BEResults )
723+ beres. df[:var ]
699724end
0 commit comments