-
Notifications
You must be signed in to change notification settings - Fork 30
Expand file tree
/
Copy pathtableDS.R
More file actions
222 lines (191 loc) · 7.33 KB
/
tableDS.R
File metadata and controls
222 lines (191 loc) · 7.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
#' @title tableDS is the first of two serverside aggregate functions
#' called by ds.table
#' @description creates 1-dimensional, 2-dimensional and 3-dimensional
#' tables using the \code{table} function in native R.
#' @details this serverside function is the workhorse of \code{ds.table} - creating
#' the table requested in the format specified by \code{ds.table}. For more
#' information see help for \code{ds.table} in DataSHIELD and the \code{table} function
#' in native R.
#' @param rvar.transmit is a character string (in inverted commas) specifying the
#' name of the variable defining the rows in all of the 2 dimensional
#' tables that form the output. Fully specified by <rvar> argument in \code{ds.table}.
#' For more information see help for \code{ds.table}
#' @param cvar.transmit is a character string specifying the
#' name of the variable defining the columns in all of the 2 dimensional
#' tables that form the output. Fully specified by <cvar> argument in \code{ds.table}.
#' For more information see help for \code{ds.table}
#' @param stvar.transmit is a character string specifying the
#' name of the variable that indexes the separate two dimensional
#' tables in the output if the call specifies a 3 dimensional table.
#' Fully specified by <stvar> argument in \code{ds.table}.
#' For more information see help for \code{ds.table}
#' @param rvar.all.unique.levels.transmit is a character string containing all
#' unique level in rvar, across the studies, separated by ','.
#' @param cvar.all.unique.levels.transmit is a character string containing all
#' unique level in cvar, across the studies, separated by ','.
#' @param stvar.all.unique.levels.transmit is a character string containing all
#' unique level in stvar, across the studies, separated by ','.
#' @param exclude.transmit for information see help on <exclude> argument
#' of \code{ds.table}. Fully specified by <exclude> argument of \code{ds.table}
#' @param useNA.transmit for information see help on <useNA> argument
#' of \code{ds.table}. Fully specified by <useNA> argument of \code{ds.table}
#' @param force.nfilter.transmit for information see help on <force.nfilter> argument
#' of \code{ds.table}. Fully specified by <force.nfilter> argument of \code{ds.table}
#' @return For information see help for \code{ds.table}
#' @author Paul Burton for DataSHIELD Development Team, 13/11/2019
#' @export
tableDS<-function(rvar.transmit, cvar.transmit, stvar.transmit, rvar.all.unique.levels.transmit, cvar.all.unique.levels.transmit,
stvar.all.unique.levels.transmit, exclude.transmit, useNA.transmit, force.nfilter.transmit){
#########################################################################
# DataSHIELD MODULE: CAPTURE THE nfilter SETTINGS #
thr<-dsBase::listDisclosureSettingsDS() #
nfilter.tab<-as.numeric(thr$nfilter.tab) #
#nfilter.glm<-as.numeric(thr$nfilter.glm) #
#nfilter.subset<-as.numeric(thr$nfilter.subset) #
#nfilter.string<-as.numeric(thr$nfilter.string) #
#nfilter.stringShort<-as.numeric(thr$nfilter.stringShort) #
#nfilter.kNN<-as.numeric(thr$nfilter.kNN) #
#datashield.privacyLevel<-as.numeric(thr$datashield.privacyLevel) #
#########################################################################
#Force higher value of nfilter
if(!is.null(force.nfilter.transmit))
{
force.nfilter.active<-eval(parse(text=force.nfilter.transmit), envir = parent.frame())
if(force.nfilter.active<nfilter.tab)
{
return.message<-paste0("Failed: if force.nfilter is non-null it must be >= to nfilter.tab i.e.",nfilter.tab)
stop(return.message, call. = FALSE)
}
}
else
{
force.nfilter.active<-NULL
}
if(!is.null(force.nfilter.active)&&!is.na(force.nfilter.active)&&force.nfilter.active>nfilter.tab)
{
nfilter.tab<-force.nfilter.active
}
#Activate via eval when needed
#rvar
rvar<-eval(parse(text=rvar.transmit), envir = parent.frame())
if(!is.factor(rvar))
{
rvar.all.unique.levels <- unlist(strsplit(rvar.all.unique.levels.transmit,split=","))
rvar<-factor(as.factor(rvar), levels=rvar.all.unique.levels)
}else{
rvar.all.unique.levels <- unlist(strsplit(rvar.all.unique.levels.transmit,split=","))
rvar<-factor(rvar, levels=rvar.all.unique.levels)
}
#cvar
if(!is.null(cvar.transmit))
{
cvar<-eval(parse(text=cvar.transmit), envir = parent.frame())
if(!is.factor(cvar))
{
cvar.all.unique.levels <- unlist(strsplit(cvar.all.unique.levels.transmit,split=","))
cvar<-factor(as.factor(cvar), levels=cvar.all.unique.levels)
}else{
cvar.all.unique.levels <- unlist(strsplit(cvar.all.unique.levels.transmit,split=","))
cvar<-factor(cvar, levels=cvar.all.unique.levels)
}
}
else
{
cvar<-NULL
}
#stvar
if(!is.null(stvar.transmit))
{
stvar<-eval(parse(text=stvar.transmit), envir = parent.frame())
if(!is.factor(stvar))
{
stvar.all.unique.levels<- unlist(strsplit(stvar.all.unique.levels.transmit,split=","))
stvar<-factor(as.factor(stvar), levels=stvar.all.unique.levels)
}else{
stvar.all.unique.levels<- unlist(strsplit(stvar.all.unique.levels.transmit,split=","))
stvar<-factor(stvar, levels=stvar.all.unique.levels)
}
}
else
{
stvar<-NULL
}
#exclude
if(!is.null(exclude.transmit))
{
exclude.text<-strsplit(exclude.transmit, split=",")
exclude<-eval(parse(text=exclude.text), envir = parent.frame())
}
else
{
exclude<-NULL
}
if(!is.null(rvar)&&!is.null(cvar)&&!is.null(stvar))
{
##Check cell counts valid without NaNs. Note: NAs need to be included as
##otherwise there's a disclosure risk when cross-tabulating.
counts.valid<-TRUE
test.outobj<-table(rvar,cvar,stvar,exclude="NaN",useNA="yes")
numcells<-length(test.outobj)
for (cell in 1:numcells)
{
if(test.outobj[cell]>0&&test.outobj[cell]<nfilter.tab)
{
counts.valid<-FALSE
}
}
if(!counts.valid)
{
return.message<-paste0("Failed: at least one cell has a non-zero count less than nfilter.tab i.e. ",nfilter.tab)
stop(return.message, call. = FALSE)
}else{
outobj<-table(rvar,cvar,stvar,exclude=exclude,useNA=useNA.transmit)
}
}
if(!is.null(rvar)&&!is.null(cvar)&&is.null(stvar))
{
##Check cell counts valid without NaNs. Note: NAs need to be included as
##otherwise there's a disclosure risk when cross-tabulating.
counts.valid<-TRUE
test.outobj<-table(rvar,cvar,exclude="NaN",useNA="yes")
numcells<-length(test.outobj)
for (cell in 1:numcells)
{
if(test.outobj[cell]>0&&test.outobj[cell]<nfilter.tab)
{
counts.valid<-FALSE
}
}
if(!counts.valid)
{
return.message<-paste0("Failed: at least one cell has a non-zero count less than nfilter.tab i.e. ",nfilter.tab)
return(return.message)
}else{
outobj<-table(rvar,cvar,exclude=exclude,useNA=useNA.transmit)
}
}
if(!is.null(rvar)&&is.null(cvar)&&is.null(stvar))
{
#Check cell counts valid without NAs or NaNs
counts.valid<-TRUE
test.outobj<-table(rvar,exclude="NaN",useNA="no")
numcells<-length(test.outobj)
for (cell in 1:numcells)
{
if(test.outobj[cell]>0&&test.outobj[cell]<nfilter.tab)
{
counts.valid<-FALSE
}
}
if(!counts.valid)
{
return.message<-paste0("Failed: at least one cell has a non-zero count less than nfilter.tab i.e. ",nfilter.tab)
return(return.message)
}else{
outobj<-table(rvar,exclude=exclude,useNA=useNA.transmit)
}
}
return(outobj)
}
#AGGREGATE FUNCTION
# tableDS