causal_hub/datasets/table/gaussian/
incomplete.rs1use std::{
2 borrow::Cow,
3 io::{Read, Write},
4 sync::Arc,
5};
6
7use csv::{ReaderBuilder, WriterBuilder};
8use ndarray::prelude::*;
9use serde::{Deserialize, Serialize};
10
11use crate::{
12 datasets::{
13 Dataset, GaussEv, GaussEvT, GaussTable, GaussType, GaussWtdTable, IncDataset,
14 MissingMechanism, MissingTable,
15 },
16 estimators::{BE, CPDEstimator},
17 io::CsvIO,
18 labels,
19 models::{CPD, GaussSupport, HasLabels},
20 set,
21 types::{Error, Labels, Result, Set},
22};
23
24#[derive(Clone, Debug, Serialize, Deserialize)]
26pub struct GaussIncTable {
27 labels: Labels,
28 values: Array2<GaussType>,
29 missing: MissingTable,
30}
31
32pub struct GaussIncTableEvidenceIter<'a> {
34 rows: ndarray::iter::LanesIter<'a, GaussType, Ix1>,
35 labels: &'a Labels,
36}
37
38impl<'a> Iterator for GaussIncTableEvidenceIter<'a> {
39 type Item = Result<GaussEv>;
40
41 fn next(&mut self) -> Option<Self::Item> {
42 let row = self.rows.next()?;
43
44 let evidences = row.iter().enumerate().filter_map(|(event, &value)| {
45 (!value.is_nan()).then_some(GaussEvT::CertainPositive { event, value })
46 });
47
48 Some(GaussEv::new(self.labels.clone(), evidences))
49 }
50}
51
52impl HasLabels for GaussIncTable {
53 #[inline]
54 fn labels(&self) -> &Labels {
55 &self.labels
56 }
57}
58
59impl GaussIncTable {
60 pub fn new(mut labels: Labels, mut values: Array2<GaussType>) -> Result<Self> {
62 if labels.len() != values.ncols() {
64 return Err(Error::IncompatibleShape(
65 &labels.len().to_string(),
66 &values.ncols().to_string(),
67 ));
68 }
69
70 if !labels.is_sorted() {
72 let mut indices: Vec<usize> = (0..labels.len()).collect();
74 indices.sort_by_key(|&i| &labels[i]);
76 labels.sort();
78 let mut new_values = values.clone();
80 indices.into_iter().enumerate().for_each(|(i, j)| {
82 new_values.column_mut(i).assign(&values.column(j));
83 });
84 values = new_values;
86 }
87
88 let missing_mask = values.mapv(|x| x.is_nan());
90 let missing = MissingTable::new(labels.clone(), missing_mask)?;
92
93 Ok(Self {
94 labels,
95 values,
96 missing,
97 })
98 }
99}
100
101impl Dataset for GaussIncTable {
102 type Values = Array2<GaussType>;
103 type Support = GaussSupport;
104 type Evidence = GaussEv;
105 type EvidenceIter<'a> = GaussIncTableEvidenceIter<'a>;
106
107 #[inline]
108 fn values(&self) -> &Self::Values {
109 &self.values
110 }
111
112 fn support(&self) -> Cow<'_, Self::Support> {
113 Cow::Owned(
114 self.labels
115 .iter()
116 .map(|l| (l.clone(), (f64::NEG_INFINITY, f64::INFINITY)))
117 .collect(),
118 )
119 }
120
121 fn evidence_iter(&self) -> Self::EvidenceIter<'_> {
122 GaussIncTableEvidenceIter {
123 rows: self.values.rows().into_iter(),
124 labels: &self.labels,
125 }
126 }
127
128 #[inline]
129 fn sample_size(&self) -> f64 {
130 self.values.nrows() as f64
131 }
132
133 fn select(&self, x: &Set<usize>) -> Result<Self> {
134 x.iter().try_for_each(|&i| {
136 if i >= self.values.ncols() {
137 return Err(Error::IndexOutOfBounds(i));
138 }
139 Ok(())
140 })?;
141
142 let labels: Labels = x
144 .iter()
145 .map(|&i| {
146 self.labels
147 .get_index(i)
148 .cloned()
149 .ok_or_else(|| Error::IndexOutOfBounds(i))
150 })
151 .collect::<Result<_>>()?;
152
153 let mut new_values = Array2::zeros((self.values.nrows(), x.len()));
155 x.iter().enumerate().for_each(|(j, &i)| {
157 new_values.column_mut(j).assign(&self.values.column(i));
158 });
159 let values = new_values;
161
162 Self::new(labels, values)
164 }
165}
166
167impl IncDataset for GaussIncTable {
168 type Missing = GaussType;
169 const MISSING: Self::Missing = GaussType::NAN;
170
171 type Complete = GaussTable;
172 type Weighted = GaussWtdTable;
173
174 #[inline]
175 fn missing(&self) -> &MissingTable {
176 &self.missing
177 }
178
179 fn ipw_weights(
180 &self,
181 d_u: &Self::Complete,
182 u: &Set<usize>,
183 pr: &MissingMechanism,
184 ) -> Result<Array1<f64>> {
185 let pr_iter = u.iter().filter_map(|&ri| pr.get(&ri).map(|pri| (ri, pri)));
187 let pr_iter = pr_iter.filter(|(_, pri)| !pri.is_empty());
189
190 let beta_i = |d_u: &Self::Complete, ri: usize, pri: &Set<usize>| -> Result<Array1<f64>> {
192 let d_pri_rpri = self.pw_deletion(pri)?;
196 let d_pri_ri_rpri = self.pw_deletion(&(&set![ri] | pri))?;
197 let x_pri_rpri = d_pri_rpri.indices_from(pri, self.labels())?;
199 let x_pri_ri_rpri = d_pri_ri_rpri.indices_from(pri, self.labels())?;
200 let p_pri_rpri = BE::new(&d_pri_rpri).fit(&x_pri_rpri, &set![])?;
202 let p_pri_ri_rpri = BE::new(&d_pri_ri_rpri).fit(&x_pri_ri_rpri, &set![])?;
203
204 let x_pri_u = d_u.indices_from(pri, self.labels())?;
206
207 let mut b_pri_rpri = Array::zeros(d_u.values().nrows());
209 let mut b_pri_ri_rpri = b_pri_rpri.clone();
210 for (d_u_j, (b_pri_rpri_j, b_pri_ri_rpri_j)) in d_u
212 .values()
213 .rows()
214 .into_iter()
215 .zip(b_pri_rpri.iter_mut().zip(b_pri_ri_rpri.iter_mut()))
216 {
217 let pri_j = x_pri_u.iter().map(|&j| d_u_j[j]).collect();
219 *b_pri_rpri_j = p_pri_rpri.pf(&pri_j, &array![])?;
221 *b_pri_ri_rpri_j = p_pri_ri_rpri.pf(&pri_j, &array![])?;
222 }
223 Ok(b_pri_rpri / b_pri_ri_rpri)
225 };
226
227 let mut beta = Array::ones(d_u.values().nrows());
229 for (ri, pri) in pr_iter {
230 let beta_i = beta_i(d_u, ri, pri)?;
231 beta *= &beta_i;
232 }
233
234 if beta.sum() > 0. {
236 beta *= (beta.len() as f64) / beta.sum();
237 }
238
239 Ok(beta)
240 }
241
242 fn lw_deletion(&self) -> Result<Self::Complete> {
243 let mut new_values = Array::zeros((
245 self.missing.complete_rows_count(), self.values.ncols(),
247 ));
248
249 let rows = self
251 .values
252 .rows()
253 .into_iter()
254 .filter(|row| row.iter().all(|&x| !x.is_nan()));
255
256 new_values
258 .rows_mut()
259 .into_iter()
260 .zip(rows)
261 .for_each(|(mut new_row, row)| new_row.assign(&row));
262
263 Self::Complete::new(self.labels.clone(), new_values)
265 }
266
267 fn pw_deletion(&self, x: &Set<usize>) -> Result<Self::Complete> {
268 if x.is_empty() {
270 let stats = labels![];
271 let v = Array::default((0, 0));
272 return GaussTable::new(stats, v);
273 }
274
275 x.iter().try_for_each(|&i| {
277 if i >= self.values.ncols() {
278 return Err(Error::IndexOutOfBounds(i));
279 }
280 Ok(())
281 })?;
282
283 let mut cols: Vec<usize> = x.iter().cloned().collect();
285 cols.sort();
287
288 let rows: Vec<_> = self
290 .values
291 .rows()
292 .into_iter()
293 .enumerate()
294 .filter_map(|(i, row)| {
295 if cols.iter().all(|&j| !row[j].is_nan()) {
297 Some(i)
298 } else {
299 None
300 }
301 })
302 .collect();
303
304 let new_values = Array::from_shape_fn(
306 (rows.len(), cols.len()), |(i, j)| self.values[[rows[i], cols[j]]],
308 );
309
310 let new_labels = cols
312 .iter()
313 .map(|&j| {
314 self.labels
315 .get_index(j)
316 .cloned()
317 .ok_or_else(|| Error::IndexOutOfBounds(j))
318 })
319 .collect::<Result<_>>()?;
320
321 Self::Complete::new(new_labels, new_values)
323 }
324
325 fn ipw_deletion(&self, x: &Set<usize>, pr: &MissingMechanism) -> Result<Self::Weighted> {
326 if x.is_empty() {
328 let stats = labels![];
329 let v = Array::default((0, 0));
330 let w = Array::default(0);
331 return Self::Weighted::new(Self::Complete::new(stats, v)?, w);
332 }
333
334 x.iter().try_for_each(|&i| {
336 if i >= self.values.ncols() {
337 return Err(Error::IndexOutOfBounds(i));
338 }
339 Ok(())
340 })?;
341 pr.keys().try_for_each(|&i| {
343 if i >= self.values.ncols() {
344 return Err(Error::IndexOutOfBounds(i));
345 }
346 Ok(())
347 })?;
348 if !pr.keys().is_sorted() {
350 return Err(Error::InvalidParameter(
351 "missing_mechanism",
352 "keys must be sorted.",
353 ));
354 }
355 if !pr.values().all(|pri| pri.iter().is_sorted()) {
356 return Err(Error::InvalidParameter(
357 "missing_mechanism",
358 "values must be sorted.",
359 ));
360 }
361
362 let mut u = x.clone();
364 let mut pru: Set<_> = x
365 .iter()
366 .flat_map(|&x| pr.get(&x).cloned())
367 .flatten()
368 .collect();
369 while !pru.is_subset(&u) {
371 u.extend(pru.drain(..));
372 pru.extend(u.iter().flat_map(|&u| pr.get(&u).cloned()).flatten());
373 }
374 u.sort();
376
377 let d_u = self.pw_deletion(&u)?;
379 let b_u = self.ipw_weights(&d_u, &u, pr)?;
381
382 let x = d_u.indices_from(x, self.labels())?;
384 let d_x = d_u.select(&x)?;
386
387 Self::Weighted::new(d_x, b_u)
389 }
390
391 fn aipw_deletion(&self, x: &Set<usize>, pr: &MissingMechanism) -> Result<Self::Weighted> {
392 if x.is_empty() {
394 let l = labels![];
395 let v = Array::default((0, 0));
396 let w = Array::default(0);
397 return Self::Weighted::new(Self::Complete::new(l, v)?, w);
398 }
399
400 x.iter().try_for_each(|&i| {
402 if i >= self.values.ncols() {
403 return Err(Error::IndexOutOfBounds(i));
404 }
405 Ok(())
406 })?;
407 pr.keys().try_for_each(|&i| {
409 if i >= self.values.ncols() {
410 return Err(Error::IndexOutOfBounds(i));
411 }
412 Ok(())
413 })?;
414 if !pr.keys().is_sorted() {
416 return Err(Error::InvalidParameter(
417 "missing_mechanism",
418 "keys must be sorted.",
419 ));
420 }
421 if !pr.values().all(|pri| pri.iter().is_sorted()) {
422 return Err(Error::InvalidParameter(
423 "missing_mechanism",
424 "values must be sorted.",
425 ));
426 }
427
428 let mut w = x.clone();
430 let prw: Set<_> = x
431 .iter()
432 .flat_map(|x| pr.get(x).cloned())
433 .flatten()
434 .collect();
435 w.sort();
437
438 let v_m = self.missing().partially_observed();
440 if (&(&prw - &w) & v_m).is_empty() {
442 return self.ipw_deletion(x, pr); };
444
445 let d_x = self.pw_deletion(x)?;
447 let b_x = Array::ones(d_x.values().nrows()); Self::Weighted::new(d_x, b_x)
450 }
451}
452
453impl CsvIO for GaussIncTable {
454 fn from_csv_reader<R: Read>(reader: R) -> Result<Self> {
455 let mut reader = ReaderBuilder::new().has_headers(true).from_reader(reader);
457
458 if !reader.has_headers() {
460 return Err(Error::MissingHeader());
461 }
462
463 let labels: Labels = reader
465 .headers()?
466 .into_iter()
467 .map(|x| x.to_owned())
468 .collect();
469
470 let values: Vec<GaussType> =
472 reader
473 .into_records()
474 .try_fold(Vec::new(), |mut values, row| -> Result<_> {
475 let row = row.map_err(|evidence| Error::Csv(Arc::new(evidence)))?;
477 values.extend(
479 row.iter()
480 .map(|x| x.parse::<GaussType>().unwrap_or(Self::MISSING)),
481 );
482 Ok(values)
483 })?;
484
485 let values = Array1::from_vec(values);
487
488 let ncols = labels.len();
490 let nrows = values.len() / ncols;
491 let values = values.into_shape_with_order((nrows, ncols))?;
493
494 Self::new(labels, values)
496 }
497
498 fn to_csv_writer<W: Write>(&self, writer: W) -> Result<()> {
499 let mut writer = WriterBuilder::new().has_headers(true).from_writer(writer);
501
502 writer.write_record(self.labels.iter())?;
504
505 for row in self.values.rows() {
507 let record = row.iter().map(|&x| {
509 if x.is_nan() {
510 "".to_string()
511 } else {
512 x.to_string()
513 }
514 });
515 writer.write_record(record)?;
517 }
518
519 Ok(())
520 }
521}