|
1 | 1 | """ |
2 | 2 | get_dummy(df::DataFrames.DataFrame, cVar::Symbol, |
3 | | - cType::String, trtRef::Nothing) |
| 3 | + cType::String, trtRef::Union{Nothing,String}=nothing) |
4 | 4 |
|
5 | | -Convert categorical variable to dummy indicators using specified contrast |
6 | | -type. This covers all cases except for treatment contrasts with a specified |
7 | | -reference level. |
| 5 | +Convert a categorical variable to dummy indicators using the specified |
| 6 | +contrast type. |
8 | 7 |
|
9 | | -# Arguments |
| 8 | +# Arguments |
10 | 9 |
|
11 | | -- `df::DataFrames.DataFrame`: DataFrame of variables |
12 | | -- `cVar::Symbol`: symbol for the categorical variable in df to be converted |
13 | | -- `cType::String`: character string indicating the type of contrast to use for `cVar` |
14 | | -- `trtRef::Nothing`: nothing |
| 10 | +- `df::DataFrames.DataFrame`: DataFrame containing the variables. |
| 11 | +- `cVar::Symbol`: column name in `df` for the categorical variable. |
| 12 | +- `cType::String`: contrast type to use. Supported values are |
| 13 | + "treat", "sum", "noint", and "sumnoint". |
| 14 | +- `trtRef::Union{Nothing,String}`: optional reference level for "treat" |
| 15 | + or "sum" contrasts. When omitted (`nothing` or an empty string), |
| 16 | + the reference defaults to the last sorted level for "treat" contrasts |
| 17 | + and the first sorted level for "sum" contrasts. |
15 | 18 |
|
16 | 19 | # Value |
17 | 20 |
|
18 | | -DataFrame of dummy variables for the specified categorical variable |
| 21 | +DataFrame containing the dummy variables for the specified categorical |
| 22 | +variable. |
19 | 23 |
|
20 | 24 | """ |
21 | | -function get_dummy(df::DataFrames.DataFrame, cVar::Symbol, cType::String, |
22 | | - trtRef::Nothing) |
23 | | - # Obtain the levels to use for the dummy indicators, depending on |
24 | | - # contrast type |
25 | | - thisVar = string.(df[:,cVar]) |
26 | | - if cType=="treat" |
27 | | - levs = unique(thisVar)[2:end] |
28 | | - elseif (cType=="sum") |
29 | | - levs = unique(thisVar)[(2:end).-1] |
30 | | - elseif cType=="noint" || (cType=="sumnoint") |
31 | | - levs = unique(thisVar) |
32 | | - else |
33 | | - error(string("Did not recognize contrast type for ", cVar)) |
34 | | - end |
35 | | - |
36 | | - # Iterate through levels to make dummy indicators |
37 | | - namedict = Dict(zip(levs, 1:length(levs))) |
38 | | - dummies = zeros(length(thisVar), length(namedict)) |
39 | | - for i=1:length(thisVar) |
40 | | - if haskey(namedict, thisVar[i]) |
41 | | - dummies[i, namedict[thisVar[i]]] = 1 |
42 | | - end |
43 | | - end |
44 | | - |
45 | | - # Some additional modifications for sum contrasts |
46 | | - if (cType=="sum") |
47 | | - dummies[thisVar.==(unique(thisVar)[end]),:] .= -1 |
48 | | - end |
49 | | - if cType=="sumnoint" |
50 | | - dummies = dummies - (1/length(unique(thisVar))) |
51 | | - end |
52 | | - |
53 | | - # Convert results to a DataFrame and rename columns |
54 | | - # newDf = convert(DataFrame, dummies) |
55 | | - newDf = DataFrame(dummies ,:auto) |
56 | | - rename!(newDf, [Symbol("$(cVar)_$k") for k in levs]) |
57 | | - return newDf |
58 | | -end |
59 | | - |
60 | | - |
61 | | -""" |
62 | | - get_dummy(df::DataFrames.DataFrame, cVar::Symbol, |
63 | | - cType::String, trtRef::String) |
| 25 | +function get_dummy(df::DataFrames.DataFrame, cVar::Symbol, cType::String, |
| 26 | + trtRef::Union{Nothing,String}=nothing) |
64 | 27 |
|
65 | | -Convert categorical variables to for treatment contrasts with a specified |
66 | | -reference level. |
| 28 | + # Convert levels to strings and compute sorted unique values once |
| 29 | + thisVar = string.(df[:, cVar]) |
| 30 | + sortedLevs = sort(unique(thisVar)) |
67 | 31 |
|
68 | | -# Arguments |
69 | | -
|
70 | | -- `df::DataFrames.DataFrame`: DataFrame of variables |
71 | | -- `cVar::Symbol`: symbol for the categorical variable in df to be converted |
72 | | -- `cType::String`: character string indicating the type of contrast to use for `cVar` |
73 | | -- `trtRef::String`: character string specifying the level in cVar to use as the reference |
| 32 | + isempty(sortedLevs) && return DataFrame() |
74 | 33 |
|
75 | | -# Value |
| 34 | + # Normalise the optional reference argument |
| 35 | + refProvided = !(trtRef === nothing || (isa(trtRef, String) && isempty(trtRef))) |
| 36 | + reference = nothing |
76 | 37 |
|
77 | | -DataFrame of dummy variables for the specified categorical variable |
| 38 | + if cType == "treat" || cType == "sum" |
| 39 | + if refProvided |
| 40 | + reference = trtRef::String |
| 41 | + if !(reference in sortedLevs) |
| 42 | + error("Reference level '" * reference * "' not found in variable " * string(cVar) * |
| 43 | + ". Available levels: " * join(sortedLevs, ", ")) |
| 44 | + end |
| 45 | + else |
| 46 | + reference = cType == "treat" ? sortedLevs[1] : sortedLevs[end] |
| 47 | + end |
| 48 | + elseif refProvided |
| 49 | + error("A reference level can only be provided for \"treat\" or \"sum\" contrasts.") |
| 50 | + end |
78 | 51 |
|
79 | | -""" |
80 | | -function get_dummy(df::DataFrames.DataFrame, cVar::Symbol, cType::String, |
81 | | - trtRef::String) |
82 | | - |
83 | | - # Obtain the levels to use for the dummy indicators. |
84 | | - thisVar = string.(df[:,cVar]) |
85 | | - if cType=="treat" |
86 | | - levs = unique(thisVar)[unique(thisVar) .!= trtRef] |
| 52 | + # Determine levels used to create indicator columns |
| 53 | + levs = if cType == "treat" |
| 54 | + filter(x -> x != reference, sortedLevs) |
| 55 | + elseif cType == "sum" |
| 56 | + filter(x -> x != reference, sortedLevs) |
| 57 | + elseif cType == "noint" || cType == "sumnoint" |
| 58 | + sortedLevs |
87 | 59 | else |
88 | | - error("Can only specify trtRef for treatment contrasts.") |
| 60 | + error("Did not recognize contrast type '" * cType * "' for " * string(cVar) * |
| 61 | + ". Valid options: \"treat\", \"sum\", \"noint\", \"sumnoint\"") |
89 | 62 | end |
90 | | - |
91 | | - # Iterate through levels to make dummy indicators |
| 63 | + |
92 | 64 | namedict = Dict(zip(levs, 1:length(levs))) |
93 | | - dummies = zeros(length(thisVar), length(namedict)) |
94 | | - for i=1:length(thisVar) |
| 65 | + dummies = zeros(Float64, length(thisVar), length(namedict)) |
| 66 | + |
| 67 | + for i in 1:length(thisVar) |
95 | 68 | if haskey(namedict, thisVar[i]) |
96 | | - dummies[i, namedict[thisVar[i]]] = 1 |
| 69 | + dummies[i, namedict[thisVar[i]]] = 1.0 |
97 | 70 | end |
98 | 71 | end |
99 | | - |
100 | | - # Convert results to a DataFrame and rename columns |
101 | | - newDf = DataFrame(dummies ,:auto) |
| 72 | + |
| 73 | + if cType == "sum" && reference !== nothing |
| 74 | + refMask = thisVar .== reference |
| 75 | + if any(refMask) && !isempty(levs) |
| 76 | + dummies[refMask, :] .= -1.0 |
| 77 | + end |
| 78 | + elseif cType == "sumnoint" |
| 79 | + dummies .= dummies .- (1.0 / length(sortedLevs)) |
| 80 | + end |
| 81 | + |
| 82 | + newDf = DataFrame(dummies, :auto) |
102 | 83 | rename!(newDf, [Symbol("$(cVar)_$k") for k in levs]) |
| 84 | + |
103 | 85 | return newDf |
104 | 86 | end |
105 | 87 |
|
@@ -175,3 +157,4 @@ function contr(df::DataFrames.DataFrame, cVars::AbstractArray{Symbol,1}, |
175 | 157 |
|
176 | 158 | return newDf |
177 | 159 | end |
| 160 | + |
0 commit comments