biplotpy 0.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
biplotpy/classical.py ADDED
@@ -0,0 +1,159 @@
1
+ """Classical biplots: GH (CMP), JK (RMP), SQRT and HJ-Biplot.
2
+
3
+ Port of ``PCA.Biplot`` and ``HJ.Biplot`` (MultBiplotR, Vicente-Villardón).
4
+ With the singular value decomposition X = U D V' of the transformed data:
5
+
6
+ * alpha = 1 : JK / RMP-Biplot rows A = U D, columns B = V
7
+ * alpha = 0 : GH / CMP-Biplot rows A = U, columns B = V D
8
+ * alpha = 0.5: SQRT biplot rows A = U D^{1/2}, columns B = V D^{1/2}
9
+ * HJ-Biplot (Galindo, 1986): A = U D and B = V D, both with optimal quality.
10
+
11
+ For alpha <= 1 the markers are rescaled by a common factor so that rows and
12
+ columns have comparable spread (``scale_factor``), as in MultBiplotR.
13
+ """
14
+ from __future__ import annotations
15
+
16
+ import numpy as np
17
+ import pandas as pd
18
+
19
+ from .transforms import initial_transform, transform_name
20
+
21
+
22
+ class ContinuousBiplot:
23
+ """Result of a classical biplot (fields mirror MultBiplotR's ``ContinuousBiplot``)."""
24
+
25
+ def __init__(self, **kw):
26
+ self.__dict__.update(kw)
27
+
28
+ # labelled views ---------------------------------------------------------
29
+ def _df(self, M, idx):
30
+ return pd.DataFrame(M, index=idx, columns=[f"Dim {d + 1}" for d in range(M.shape[1])])
31
+
32
+ @property
33
+ def rows(self):
34
+ return self._df(self.row_coordinates, self.row_names)
35
+
36
+ @property
37
+ def columns(self):
38
+ return self._df(self.col_coordinates, self.col_names)
39
+
40
+ def qualities(self, which="columns"):
41
+ """Quality of representation: cumulative relative contributions (%)."""
42
+ if which == "columns":
43
+ return self._df(np.cumsum(self.col_contributions, 1), self.col_names)
44
+ return self._df(np.cumsum(self.row_contributions, 1), self.row_names)
45
+
46
+ def summary(self) -> dict:
47
+ d = self.dim
48
+ eig = pd.DataFrame({"Eigenvalue": self.eigenvalues[:d], "Exp. Var": self.inertia[:d],
49
+ "Cumulative": self.cum_inertia[:d]}, index=[f"Dim {i + 1}" for i in range(d)])
50
+ return {"eigen": eig,
51
+ "col_contributions": self._df(self.col_contributions, self.col_names),
52
+ "col_qualities": self.qualities("columns"),
53
+ "row_contributions": self._df(self.row_contributions, self.row_names),
54
+ "row_qualities": self.qualities("rows"),
55
+ "structure": self._df(self.structure, self.col_names),
56
+ "row_contrib_to_factor": self._df(self.row_contrib_to_factor, self.row_names),
57
+ "col_contrib_to_factor": self._df(self.col_contrib_to_factor, self.col_names)}
58
+
59
+ def plot(self, *args, **kwargs):
60
+ from .plot import plot_biplot
61
+ return plot_biplot(self, *args, **kwargs)
62
+
63
+ def __repr__(self):
64
+ s = self.summary()
65
+ return (f"{self.title} ({self.normalization}); transformation: {self.transformation}\n"
66
+ f"{s['eigen'].round(3).to_string()}\n\nQuality of representation of the columns (%):\n"
67
+ f"{s['col_qualities'].round(2).to_string()}")
68
+
69
+
70
+ _NORMALIZATION = {2: "Principal normalization (HJ-Biplot)", 1: "Row principal normalization (JK / RMP-Biplot)",
71
+ 0: "Column principal normalization (GH / CMP-Biplot)", 0.5: "Symmetrical normalization (SQRT-Biplot)"}
72
+
73
+
74
+ def pca_biplot(X, alpha=1.0, dim=2, scaling=5, sup_rows=None, sup_cols=None, grouping=None,
75
+ row_names=None, col_names=None) -> ContinuousBiplot:
76
+ """Classical PCA biplot with normalization ``alpha`` (``alpha > 1`` gives the HJ-Biplot).
77
+
78
+ ``scaling`` is the initial transformation (name or MultBiplotR number; 5 =
79
+ standardize columns, 4 = column centering).
80
+ """
81
+ if isinstance(X, pd.DataFrame):
82
+ row_names = row_names or [str(i) for i in X.index]
83
+ col_names = col_names or [str(c) for c in X.columns]
84
+ X = X.to_numpy(float)
85
+ X0 = np.array(X, float)
86
+ n, p = X0.shape
87
+ row_names = list(row_names) if row_names is not None else [f"I{i + 1}" for i in range(n)]
88
+ col_names = list(col_names) if col_names is not None else [f"V{j + 1}" for j in range(p)]
89
+ tr = initial_transform(X0, transform_name(scaling), sup_rows, sup_cols, grouping)
90
+ Xs = tr["X"]
91
+ U, d, Vt = np.linalg.svd(Xs, full_matrices=False)
92
+ V = Vt.T
93
+ ev = d ** 2
94
+ inertia = ev / ev.sum() * 100
95
+ a = U[:, :dim] * d[:dim]
96
+ b = V[:, :dim] * d[:dim]
97
+ structure = np.corrcoef(np.column_stack([Xs, a]), rowvar=False)[:p, p:]
98
+ sf = (Xs ** 2).sum(1)
99
+ rc = a ** 2 / sf[:, None] * 100
100
+ scc = (Xs ** 2).sum(0)
101
+ cc = b ** 2 / scc[:, None] * 100
102
+ # contributions of each element to the factor (absolute contributions, %)
103
+ rcf = a ** 2 / (a ** 2).sum(0) * 100
104
+ ccf = b ** 2 / (b ** 2).sum(0) * 100
105
+ sr, sc = tr["sup_rows"], tr["sup_cols"]
106
+ a_s = b_s = None
107
+ if sr is not None:
108
+ a_s = sr @ V[:, :dim]
109
+ rcs = a_s ** 2 / (sr ** 2).sum(1)[:, None] * 100
110
+ if sc is not None:
111
+ b_s = sc.T @ U[:, :dim]
112
+ ccs = b_s ** 2 / (sc ** 2).sum(0)[:, None] * 100
113
+ if alpha <= 1:
114
+ a = a * (1 / d[:dim]) ** (1 - alpha)
115
+ b = b * (1 / d[:dim]) ** alpha
116
+ if a_s is not None:
117
+ a_s = a_s * (1 / d[:dim]) ** (1 - alpha)
118
+ if b_s is not None:
119
+ b_s = b_s * (1 / d[:dim]) ** alpha
120
+ sca = (a ** 2).sum() / n
121
+ scb = (b ** 2).sum() / p
122
+ scf = np.sqrt(np.sqrt(scb / sca))
123
+ a, b = a * scf, b / scf
124
+ a_s = None if a_s is None else a_s * scf
125
+ b_s = None if b_s is None else b_s / scf
126
+ else:
127
+ scf = 1.0
128
+ norm = _NORMALIZATION.get(alpha if alpha <= 1 else 2, f"Custom normalization (alpha = {alpha})")
129
+ return ContinuousBiplot(
130
+ title="HJ Biplot" if alpha > 1 else "PCA Biplot", type="HJ" if alpha > 1 else "PCA", alpha=alpha,
131
+ normalization=norm, dim=dim, transformation=tr["transform"], non_scaled_data=X0, scaled_data=Xs,
132
+ means=X0.mean(0), medians=np.median(X0, 0), deviations=tr["col_sds"], minima=X0.min(0), maxima=X0.max(0),
133
+ p25=np.quantile(X0, 0.25, axis=0), p75=np.quantile(X0, 0.75, axis=0), gmean=X0.mean(),
134
+ eigenvalues=ev, inertia=inertia, cum_inertia=np.cumsum(inertia), V=V[:, :dim], U=U[:, :dim], d=d,
135
+ structure=structure, row_coordinates=a, col_coordinates=b, row_contributions=rc, col_contributions=cc,
136
+ row_contrib_to_factor=rcf, col_contrib_to_factor=ccf, scale_factor=scf, row_names=row_names,
137
+ col_names=col_names, n=n, p=p,
138
+ sup_row_coordinates=a_s, sup_col_coordinates=b_s,
139
+ sup_row_contributions=None if sr is None else rcs, sup_col_contributions=None if sc is None else ccs)
140
+
141
+
142
+ def hj_biplot(X, dim=3, scaling=5, **kw) -> ContinuousBiplot:
143
+ """HJ-Biplot (Galindo, 1986): rows and columns with optimal quality of representation."""
144
+ return pca_biplot(X, alpha=2, dim=dim, scaling=scaling, **kw)
145
+
146
+
147
+ def gh_biplot(X, dim=2, scaling=5, **kw) -> ContinuousBiplot:
148
+ """GH-Biplot (column metric preserving, alpha = 0)."""
149
+ return pca_biplot(X, alpha=0, dim=dim, scaling=scaling, **kw)
150
+
151
+
152
+ def jk_biplot(X, dim=2, scaling=5, **kw) -> ContinuousBiplot:
153
+ """JK-Biplot (row metric preserving, alpha = 1)."""
154
+ return pca_biplot(X, alpha=1, dim=dim, scaling=scaling, **kw)
155
+
156
+
157
+ def sqrt_biplot(X, dim=2, scaling=5, **kw) -> ContinuousBiplot:
158
+ """Symmetrical (SQRT) biplot, alpha = 0.5."""
159
+ return pca_biplot(X, alpha=0.5, dim=dim, scaling=scaling, **kw)
@@ -0,0 +1,231 @@
1
+ """Correspondence-type biplots: simple and multiple correspondence analysis,
2
+ canonical correspondence analysis (CCA) and redundancy analysis (RDA).
3
+
4
+ * ``ca`` — port of ``MultBiplotR::CA`` (alpha = 1 rows principal / columns
5
+ standard, 0 the reverse, 0.5 symmetric biplot, 2 = both principal, the
6
+ usual "symmetric map" of ``ca``/``FactoMineR``); also returns the absolute
7
+ contributions (to the axis) of ``ca::ca``/``FactoMineR::CA``.
8
+ * ``mca`` — multiple correspondence analysis as the CA of the indicator matrix
9
+ (``FactoMineR::MCA`` conventions), with the Benzécri and Greenacre adjusted
10
+ inertias.
11
+ * ``cca`` — port of ``MultBiplotR::CCA`` (ter Braak, 1986), eigenvalues equal
12
+ to ``vegan::cca``.
13
+ * ``rda`` — redundancy analysis with the scores and scalings of ``vegan::rda``.
14
+ """
15
+ from __future__ import annotations
16
+
17
+ import numpy as np
18
+ import pandas as pd
19
+
20
+ from .transforms import initial_transform, transform_name
21
+
22
+
23
+ class OrdinationBiplot:
24
+ """Result of a CA/MCA/CCA/RDA/PCoA/MDS-type biplot."""
25
+
26
+ def __init__(self, **kw):
27
+ self.__dict__.update(kw)
28
+
29
+ def __repr__(self):
30
+ ev = np.asarray(self.eigenvalues)[:5]
31
+ return f"{self.title}: eigenvalues {np.round(ev, 4)}; inertia (%) {np.round(np.asarray(self.inertia)[:5], 2)}"
32
+
33
+ def plot(self, *args, **kwargs):
34
+ from .plot import plot_ordination
35
+ return plot_ordination(self, *args, **kwargs)
36
+
37
+
38
+ def _names(x, n, p, rp="I", cp="V"):
39
+ if isinstance(x, pd.DataFrame):
40
+ return [str(i) for i in x.index], [str(c) for c in x.columns]
41
+ return [f"{rp}{i + 1}" for i in range(n)], [f"{cp}{j + 1}" for j in range(p)]
42
+
43
+
44
+ # --------------------------------------------------------------------------- CA
45
+ def ca(N, dim=2, alpha=2.0, sup_rows=None, sup_cols=None) -> OrdinationBiplot:
46
+ """Simple correspondence analysis of a contingency table ``N``.
47
+
48
+ ``alpha``: 2 = symmetric map (rows and columns in principal coordinates);
49
+ 1 = row principal (RMP); 0 = column principal (CMP); 0.5 = symmetric
50
+ biplot (MultBiplotR's convention for alpha <= 1)."""
51
+ rn, cn = _names(N, *np.shape(N))
52
+ X = np.asarray(N, float)
53
+ n, p = X.shape
54
+ tot = X.sum()
55
+ P = X / tot
56
+ r, c = P.sum(1), P.sum(0)
57
+ S = (P - np.outer(r, c)) / np.sqrt(np.outer(r, c))
58
+ U, d, Vt = np.linalg.svd(S, full_matrices=False)
59
+ k = min(n, p) - 1
60
+ U, d, V = U[:, :k], d[:k], Vt.T[:, :k]
61
+ Fs, Gs = U / np.sqrt(r)[:, None], V / np.sqrt(c)[:, None] # standard coordinates
62
+ F, G = Fs * d, Gs * d # principal coordinates
63
+ ev = d ** 2
64
+ inertia = ev / ev.sum() * 100
65
+ qual_r = F ** 2 / (F ** 2).sum(1, keepdims=True) * 100
66
+ qual_c = G ** 2 / (G ** 2).sum(1, keepdims=True) * 100
67
+ ctr_r = r[:, None] * F ** 2 / ev * 100
68
+ ctr_c = c[:, None] * G ** 2 / ev * 100
69
+ if alpha > 1:
70
+ A, B = F, G
71
+ else:
72
+ A, B = Fs * d ** alpha, Gs * d ** (1 - alpha)
73
+ res = OrdinationBiplot(title="Correspondence Analysis", type="CA", alpha=alpha, dim=dim, eigenvalues=ev,
74
+ inertia=inertia, cum_inertia=np.cumsum(inertia), total_inertia=ev.sum(),
75
+ chi2=ev.sum() * tot, row_coordinates=A[:, :dim], col_coordinates=B[:, :dim],
76
+ row_principal=F, col_principal=G, row_standard=Fs, col_standard=Gs,
77
+ row_masses=r, col_masses=c, row_qualities=qual_r[:, :dim], col_qualities=qual_c[:, :dim],
78
+ row_contributions=ctr_r[:, :dim], col_contributions=ctr_c[:, :dim],
79
+ row_names=rn, col_names=cn, data=X)
80
+ if sup_rows is not None:
81
+ R = np.asarray(sup_rows, float); R = R / R.sum(1, keepdims=True)
82
+ res.sup_row_coordinates = (R @ Gs)[:, :dim]
83
+ if sup_cols is not None:
84
+ C = np.asarray(sup_cols, float); C = C / C.sum(0, keepdims=True)
85
+ res.sup_col_coordinates = (C.T @ Fs)[:, :dim]
86
+ return res
87
+
88
+
89
+ # --------------------------------------------------------------------------- MCA
90
+ def indicator_matrix(X):
91
+ """Complete disjunctive table of a data frame of categorical variables."""
92
+ df = pd.DataFrame(X).astype(str)
93
+ cols, levs, var_of = [], [], []
94
+ for v in df.columns:
95
+ for lev in sorted(df[v].unique()):
96
+ cols.append((df[v] == lev).astype(float).to_numpy())
97
+ levs.append(lev); var_of.append(v)
98
+ # category labels as in FactoMineR: the level itself when unique, else variable_level
99
+ names = levs if len(set(levs)) == len(levs) else [f"{v}_{l}" for v, l in zip(var_of, levs)]
100
+ return np.column_stack(cols), names, var_of
101
+
102
+
103
+ def mca(X, dim=2, sup_rows=None) -> OrdinationBiplot:
104
+ """Multiple correspondence analysis (CA of the indicator matrix).
105
+
106
+ Coordinates follow ``FactoMineR::MCA``: individuals and categories in
107
+ principal coordinates; eigenvalues of the indicator matrix; also the
108
+ Benzécri-corrected and Greenacre-adjusted percentages of inertia."""
109
+ df = pd.DataFrame(X)
110
+ rn = [str(i) for i in df.index]
111
+ Z, names, var_of = indicator_matrix(df)
112
+ Q = df.shape[1]
113
+ res = ca(pd.DataFrame(Z, index=rn, columns=names), dim=max(dim, 2), alpha=2)
114
+ ev = res.eigenvalues
115
+ keep = ev > 1 / Q
116
+ benz = ((Q / (Q - 1)) * (ev[keep] - 1 / Q)) ** 2
117
+ J = Z.shape[1]
118
+ green_total = Q / (Q - 1) * (np.sum(ev ** 2) - (J - Q) / Q ** 2)
119
+ res.title, res.type = "Multiple Correspondence Analysis", "MCA"
120
+ res.row_coordinates, res.col_coordinates = res.row_principal[:, :dim], res.col_principal[:, :dim]
121
+ res.benzecri = benz / benz.sum() * 100
122
+ res.greenacre = benz / green_total * 100
123
+ res.variables = var_of
124
+ res.eta2 = np.array([[np.sum(res.col_masses[np.array(var_of) == v] * res.col_principal[np.array(var_of) == v, k] ** 2)
125
+ * Q for k in range(dim)] for v in df.columns])
126
+ res.var_names = list(df.columns)
127
+ return res
128
+
129
+
130
+ # --------------------------------------------------------------------------- CCA
131
+ def _msqrt(S, inv=False):
132
+ w, U = np.linalg.eigh(S)
133
+ w = np.maximum(w, 0)
134
+ return U @ np.diag(1 / np.sqrt(w) if inv else np.sqrt(w)) @ U.T
135
+
136
+
137
+ def cca(Y, Z, alpha=1.0, dim=2) -> OrdinationBiplot:
138
+ """Canonical correspondence analysis of an abundance table ``Y`` (sites x
139
+ species) constrained by environmental variables ``Z`` (sites x variables).
140
+
141
+ Port of ``MultBiplotR::CCA``: species scores, site scores (weighted
142
+ averages, WA) and linear-combination site scores (LC), environmental
143
+ variable scores (biplot arrows), qualities and inertia decompositions.
144
+ ``alpha`` = 1 gives species in principal coordinates."""
145
+ sn, spn = _names(Y, *np.shape(Y), "Si", "Sp")
146
+ en = list(Z.columns) if isinstance(Z, pd.DataFrame) else [f"Ev{k + 1}" for k in range(np.shape(Z)[1])]
147
+ P = np.asarray(Y, float); Zm = np.asarray(Z, float)
148
+ P = P / P.sum()
149
+ r, c = P.sum(1), P.sum(0)
150
+ PC = (P - np.outer(r, c)) / np.sqrt(np.outer(r, c))
151
+ valsin = np.linalg.svd(PC, compute_uv=False)
152
+ in_total = np.sum(PC ** 2)
153
+ iner_rows, iner_cols = (PC ** 2).sum(1), (PC ** 2).sum(0)
154
+ W1 = (P.T @ Zm) / c[:, None]
155
+ mean_z = r @ Zm
156
+ Zc = Zm - mean_z
157
+ s11 = r @ Zc ** 2
158
+ Zs = Zc / np.sqrt(s11)
159
+ W = (P.T @ Zs) / c[:, None]
160
+ S22 = Zs.T @ (r[:, None] * Zs)
161
+ sq, isq = _msqrt(S22), _msqrt(S22, inv=True)
162
+ WW = np.sqrt(c)[:, None] * W @ isq
163
+ U, d, Vt = np.linalg.svd(WW, full_matrices=False)
164
+ V = Vt.T
165
+ x = (P / r[:, None]) @ (U / np.sqrt(c)[:, None])
166
+ x2 = Zs @ isq @ V
167
+ A = (U / np.sqrt(c)[:, None]) * d ** alpha
168
+ B = sq @ V * d ** (1 - alpha)
169
+ Afull = (U / np.sqrt(c)[:, None]) * d
170
+ Bfull = sq @ V * d
171
+ sp_q = Afull ** 2 / (Afull ** 2).sum(1, keepdims=True) * 100
172
+ ev_q = Bfull ** 2 / (Bfull ** 2).sum(1, keepdims=True) * 100
173
+ site_q = (np.sqrt(r)[:, None] * x) ** 2 / iner_rows[:, None] * 100
174
+ sp_q_ca = (U * d) ** 2 / iner_cols[:, None] * 100
175
+ interset = np.corrcoef(np.column_stack([x, Zm]), rowvar=False)[:x.shape[1], x.shape[1]:]
176
+ ev = d ** 2
177
+ return OrdinationBiplot(title="Canonical Correspondence Analysis", type="CCA", alpha=alpha, dim=dim,
178
+ eigenvalues=ev, inertia=ev / ev.sum() * 100, exp_species_constrained=ev / in_total * 100,
179
+ exp_species_ca=valsin ** 2 / in_total * 100, total_inertia=in_total,
180
+ row_coordinates=(x * d ** (-alpha))[:, :dim], lc_site_scores=(x2 * d ** (-alpha))[:, :dim],
181
+ col_coordinates=A[:, :dim], env_coordinates=B[:, :dim], weighted_averages=W1,
182
+ species_quality=sp_q[:, :dim], species_quality_ca=sp_q_ca[:, :dim],
183
+ env_quality=ev_q[:, :dim], site_quality=site_q[:, :dim], interset=interset[:, :dim],
184
+ row_names=sn, col_names=spn, env_names=en, means_z=mean_z, sd_z=np.sqrt(s11))
185
+
186
+
187
+ # --------------------------------------------------------------------------- RDA
188
+ def rda(Y, X, scale=False, scaling=2, dim=2) -> OrdinationBiplot:
189
+ """Redundancy analysis (constrained PCA) of ``Y`` on ``X``.
190
+
191
+ Scores and scalings follow ``vegan::rda``/``scores.rda`` (scaling 1 =
192
+ sites, 2 = species, 3 = symmetric; constant sqrt(sqrt((n-1) * total
193
+ variance))): site scores (WA), constrained site scores (LC), species scores
194
+ and biplot scores of the explanatory variables; unconstrained (residual)
195
+ axes are returned as ``ca_eigenvalues``."""
196
+ sn, spn = _names(Y, *np.shape(Y), "S", "Sp")
197
+ xn = list(X.columns) if isinstance(X, pd.DataFrame) else [f"X{k + 1}" for k in range(np.shape(X)[1])]
198
+ Ym = np.asarray(Y, float); Xm = np.asarray(X, float)
199
+ n = Ym.shape[0]
200
+ Yc = Ym - Ym.mean(0)
201
+ if scale:
202
+ Yc = Yc / Ym.std(0, ddof=1)
203
+ Ys = Yc / np.sqrt(n - 1)
204
+ tot = np.sum(Ys ** 2)
205
+ Xc = Xm - Xm.mean(0)
206
+ Qx, _ = np.linalg.qr(Xc)
207
+ rank = np.linalg.matrix_rank(Xc)
208
+ Qx = Qx[:, :rank]
209
+ Fit = Qx @ (Qx.T @ Ys)
210
+ U, d, Vt = np.linalg.svd(Fit, full_matrices=False)
211
+ k = int(np.sum(d > 1e-10 * d[0]))
212
+ U, d, V = U[:, :k], d[:k], Vt.T[:, :k]
213
+ ev = d ** 2
214
+ wa = Ys @ V / d
215
+ biplot = np.corrcoef(np.column_stack([Xm, U]), rowvar=False)[:Xm.shape[1], Xm.shape[1]:]
216
+ Res = Ys - Fit
217
+ res_ev = np.linalg.svd(Res, compute_uv=False) ** 2
218
+ res_ev = res_ev[res_ev > 1e-10 * max(res_ev.max(), 1e-300)]
219
+ const = np.sqrt(np.sqrt((n - 1) * tot))
220
+ eig_all = np.concatenate([ev, res_ev])
221
+ slam = np.sqrt(ev / tot)
222
+ sp_s, site_s = {1: (1, slam), 2: (slam, 1), 3: (np.sqrt(slam), np.sqrt(slam))}[scaling]
223
+ species = const * V * sp_s
224
+ sites = const * wa * site_s
225
+ lc = const * U * site_s
226
+ bp = biplot * site_s
227
+ return OrdinationBiplot(title="Redundancy Analysis", type="RDA", dim=dim, scaling=scaling, eigenvalues=ev,
228
+ inertia=ev / tot * 100, ca_eigenvalues=res_ev, total_inertia=tot,
229
+ constrained_proportion=ev.sum() / tot, row_coordinates=sites[:, :dim],
230
+ lc_site_scores=lc[:, :dim], col_coordinates=species[:, :dim], env_coordinates=bp[:, :dim],
231
+ row_names=sn, col_names=spn, env_names=xn, const=const, all_eigenvalues=eig_all)
@@ -0,0 +1,19 @@
1
+ """Classic datasets used in the examples."""
2
+ from importlib import resources
3
+
4
+ import pandas as pd
5
+
6
+
7
+ def _read(name):
8
+ with resources.files(__package__).joinpath(name).open("r") as f:
9
+ return pd.read_csv(f)
10
+
11
+
12
+ def load_iris() -> pd.DataFrame:
13
+ """Fisher's iris data (150 x 5)."""
14
+ return _read("iris.csv")
15
+
16
+
17
+ def load_mtcars() -> pd.DataFrame:
18
+ """Motor Trend cars (32 x 12, with a ``name`` column)."""
19
+ return _read("mtcars.csv").set_index("name")
@@ -0,0 +1,151 @@
1
+ "Sepal.Length","Sepal.Width","Petal.Length","Petal.Width","Species"
2
+ 5.1,3.5,1.4,0.2,"setosa"
3
+ 4.9,3,1.4,0.2,"setosa"
4
+ 4.7,3.2,1.3,0.2,"setosa"
5
+ 4.6,3.1,1.5,0.2,"setosa"
6
+ 5,3.6,1.4,0.2,"setosa"
7
+ 5.4,3.9,1.7,0.4,"setosa"
8
+ 4.6,3.4,1.4,0.3,"setosa"
9
+ 5,3.4,1.5,0.2,"setosa"
10
+ 4.4,2.9,1.4,0.2,"setosa"
11
+ 4.9,3.1,1.5,0.1,"setosa"
12
+ 5.4,3.7,1.5,0.2,"setosa"
13
+ 4.8,3.4,1.6,0.2,"setosa"
14
+ 4.8,3,1.4,0.1,"setosa"
15
+ 4.3,3,1.1,0.1,"setosa"
16
+ 5.8,4,1.2,0.2,"setosa"
17
+ 5.7,4.4,1.5,0.4,"setosa"
18
+ 5.4,3.9,1.3,0.4,"setosa"
19
+ 5.1,3.5,1.4,0.3,"setosa"
20
+ 5.7,3.8,1.7,0.3,"setosa"
21
+ 5.1,3.8,1.5,0.3,"setosa"
22
+ 5.4,3.4,1.7,0.2,"setosa"
23
+ 5.1,3.7,1.5,0.4,"setosa"
24
+ 4.6,3.6,1,0.2,"setosa"
25
+ 5.1,3.3,1.7,0.5,"setosa"
26
+ 4.8,3.4,1.9,0.2,"setosa"
27
+ 5,3,1.6,0.2,"setosa"
28
+ 5,3.4,1.6,0.4,"setosa"
29
+ 5.2,3.5,1.5,0.2,"setosa"
30
+ 5.2,3.4,1.4,0.2,"setosa"
31
+ 4.7,3.2,1.6,0.2,"setosa"
32
+ 4.8,3.1,1.6,0.2,"setosa"
33
+ 5.4,3.4,1.5,0.4,"setosa"
34
+ 5.2,4.1,1.5,0.1,"setosa"
35
+ 5.5,4.2,1.4,0.2,"setosa"
36
+ 4.9,3.1,1.5,0.2,"setosa"
37
+ 5,3.2,1.2,0.2,"setosa"
38
+ 5.5,3.5,1.3,0.2,"setosa"
39
+ 4.9,3.6,1.4,0.1,"setosa"
40
+ 4.4,3,1.3,0.2,"setosa"
41
+ 5.1,3.4,1.5,0.2,"setosa"
42
+ 5,3.5,1.3,0.3,"setosa"
43
+ 4.5,2.3,1.3,0.3,"setosa"
44
+ 4.4,3.2,1.3,0.2,"setosa"
45
+ 5,3.5,1.6,0.6,"setosa"
46
+ 5.1,3.8,1.9,0.4,"setosa"
47
+ 4.8,3,1.4,0.3,"setosa"
48
+ 5.1,3.8,1.6,0.2,"setosa"
49
+ 4.6,3.2,1.4,0.2,"setosa"
50
+ 5.3,3.7,1.5,0.2,"setosa"
51
+ 5,3.3,1.4,0.2,"setosa"
52
+ 7,3.2,4.7,1.4,"versicolor"
53
+ 6.4,3.2,4.5,1.5,"versicolor"
54
+ 6.9,3.1,4.9,1.5,"versicolor"
55
+ 5.5,2.3,4,1.3,"versicolor"
56
+ 6.5,2.8,4.6,1.5,"versicolor"
57
+ 5.7,2.8,4.5,1.3,"versicolor"
58
+ 6.3,3.3,4.7,1.6,"versicolor"
59
+ 4.9,2.4,3.3,1,"versicolor"
60
+ 6.6,2.9,4.6,1.3,"versicolor"
61
+ 5.2,2.7,3.9,1.4,"versicolor"
62
+ 5,2,3.5,1,"versicolor"
63
+ 5.9,3,4.2,1.5,"versicolor"
64
+ 6,2.2,4,1,"versicolor"
65
+ 6.1,2.9,4.7,1.4,"versicolor"
66
+ 5.6,2.9,3.6,1.3,"versicolor"
67
+ 6.7,3.1,4.4,1.4,"versicolor"
68
+ 5.6,3,4.5,1.5,"versicolor"
69
+ 5.8,2.7,4.1,1,"versicolor"
70
+ 6.2,2.2,4.5,1.5,"versicolor"
71
+ 5.6,2.5,3.9,1.1,"versicolor"
72
+ 5.9,3.2,4.8,1.8,"versicolor"
73
+ 6.1,2.8,4,1.3,"versicolor"
74
+ 6.3,2.5,4.9,1.5,"versicolor"
75
+ 6.1,2.8,4.7,1.2,"versicolor"
76
+ 6.4,2.9,4.3,1.3,"versicolor"
77
+ 6.6,3,4.4,1.4,"versicolor"
78
+ 6.8,2.8,4.8,1.4,"versicolor"
79
+ 6.7,3,5,1.7,"versicolor"
80
+ 6,2.9,4.5,1.5,"versicolor"
81
+ 5.7,2.6,3.5,1,"versicolor"
82
+ 5.5,2.4,3.8,1.1,"versicolor"
83
+ 5.5,2.4,3.7,1,"versicolor"
84
+ 5.8,2.7,3.9,1.2,"versicolor"
85
+ 6,2.7,5.1,1.6,"versicolor"
86
+ 5.4,3,4.5,1.5,"versicolor"
87
+ 6,3.4,4.5,1.6,"versicolor"
88
+ 6.7,3.1,4.7,1.5,"versicolor"
89
+ 6.3,2.3,4.4,1.3,"versicolor"
90
+ 5.6,3,4.1,1.3,"versicolor"
91
+ 5.5,2.5,4,1.3,"versicolor"
92
+ 5.5,2.6,4.4,1.2,"versicolor"
93
+ 6.1,3,4.6,1.4,"versicolor"
94
+ 5.8,2.6,4,1.2,"versicolor"
95
+ 5,2.3,3.3,1,"versicolor"
96
+ 5.6,2.7,4.2,1.3,"versicolor"
97
+ 5.7,3,4.2,1.2,"versicolor"
98
+ 5.7,2.9,4.2,1.3,"versicolor"
99
+ 6.2,2.9,4.3,1.3,"versicolor"
100
+ 5.1,2.5,3,1.1,"versicolor"
101
+ 5.7,2.8,4.1,1.3,"versicolor"
102
+ 6.3,3.3,6,2.5,"virginica"
103
+ 5.8,2.7,5.1,1.9,"virginica"
104
+ 7.1,3,5.9,2.1,"virginica"
105
+ 6.3,2.9,5.6,1.8,"virginica"
106
+ 6.5,3,5.8,2.2,"virginica"
107
+ 7.6,3,6.6,2.1,"virginica"
108
+ 4.9,2.5,4.5,1.7,"virginica"
109
+ 7.3,2.9,6.3,1.8,"virginica"
110
+ 6.7,2.5,5.8,1.8,"virginica"
111
+ 7.2,3.6,6.1,2.5,"virginica"
112
+ 6.5,3.2,5.1,2,"virginica"
113
+ 6.4,2.7,5.3,1.9,"virginica"
114
+ 6.8,3,5.5,2.1,"virginica"
115
+ 5.7,2.5,5,2,"virginica"
116
+ 5.8,2.8,5.1,2.4,"virginica"
117
+ 6.4,3.2,5.3,2.3,"virginica"
118
+ 6.5,3,5.5,1.8,"virginica"
119
+ 7.7,3.8,6.7,2.2,"virginica"
120
+ 7.7,2.6,6.9,2.3,"virginica"
121
+ 6,2.2,5,1.5,"virginica"
122
+ 6.9,3.2,5.7,2.3,"virginica"
123
+ 5.6,2.8,4.9,2,"virginica"
124
+ 7.7,2.8,6.7,2,"virginica"
125
+ 6.3,2.7,4.9,1.8,"virginica"
126
+ 6.7,3.3,5.7,2.1,"virginica"
127
+ 7.2,3.2,6,1.8,"virginica"
128
+ 6.2,2.8,4.8,1.8,"virginica"
129
+ 6.1,3,4.9,1.8,"virginica"
130
+ 6.4,2.8,5.6,2.1,"virginica"
131
+ 7.2,3,5.8,1.6,"virginica"
132
+ 7.4,2.8,6.1,1.9,"virginica"
133
+ 7.9,3.8,6.4,2,"virginica"
134
+ 6.4,2.8,5.6,2.2,"virginica"
135
+ 6.3,2.8,5.1,1.5,"virginica"
136
+ 6.1,2.6,5.6,1.4,"virginica"
137
+ 7.7,3,6.1,2.3,"virginica"
138
+ 6.3,3.4,5.6,2.4,"virginica"
139
+ 6.4,3.1,5.5,1.8,"virginica"
140
+ 6,3,4.8,1.8,"virginica"
141
+ 6.9,3.1,5.4,2.1,"virginica"
142
+ 6.7,3.1,5.6,2.4,"virginica"
143
+ 6.9,3.1,5.1,2.3,"virginica"
144
+ 5.8,2.7,5.1,1.9,"virginica"
145
+ 6.8,3.2,5.9,2.3,"virginica"
146
+ 6.7,3.3,5.7,2.5,"virginica"
147
+ 6.7,3,5.2,2.3,"virginica"
148
+ 6.3,2.5,5,1.9,"virginica"
149
+ 6.5,3,5.2,2,"virginica"
150
+ 6.2,3.4,5.4,2.3,"virginica"
151
+ 5.9,3,5.1,1.8,"virginica"
@@ -0,0 +1,33 @@
1
+ "mpg","cyl","disp","hp","drat","wt","qsec","vs","am","gear","carb","name"
2
+ 21,6,160,110,3.9,2.62,16.46,0,1,4,4,"Mazda RX4"
3
+ 21,6,160,110,3.9,2.875,17.02,0,1,4,4,"Mazda RX4 Wag"
4
+ 22.8,4,108,93,3.85,2.32,18.61,1,1,4,1,"Datsun 710"
5
+ 21.4,6,258,110,3.08,3.215,19.44,1,0,3,1,"Hornet 4 Drive"
6
+ 18.7,8,360,175,3.15,3.44,17.02,0,0,3,2,"Hornet Sportabout"
7
+ 18.1,6,225,105,2.76,3.46,20.22,1,0,3,1,"Valiant"
8
+ 14.3,8,360,245,3.21,3.57,15.84,0,0,3,4,"Duster 360"
9
+ 24.4,4,146.7,62,3.69,3.19,20,1,0,4,2,"Merc 240D"
10
+ 22.8,4,140.8,95,3.92,3.15,22.9,1,0,4,2,"Merc 230"
11
+ 19.2,6,167.6,123,3.92,3.44,18.3,1,0,4,4,"Merc 280"
12
+ 17.8,6,167.6,123,3.92,3.44,18.9,1,0,4,4,"Merc 280C"
13
+ 16.4,8,275.8,180,3.07,4.07,17.4,0,0,3,3,"Merc 450SE"
14
+ 17.3,8,275.8,180,3.07,3.73,17.6,0,0,3,3,"Merc 450SL"
15
+ 15.2,8,275.8,180,3.07,3.78,18,0,0,3,3,"Merc 450SLC"
16
+ 10.4,8,472,205,2.93,5.25,17.98,0,0,3,4,"Cadillac Fleetwood"
17
+ 10.4,8,460,215,3,5.424,17.82,0,0,3,4,"Lincoln Continental"
18
+ 14.7,8,440,230,3.23,5.345,17.42,0,0,3,4,"Chrysler Imperial"
19
+ 32.4,4,78.7,66,4.08,2.2,19.47,1,1,4,1,"Fiat 128"
20
+ 30.4,4,75.7,52,4.93,1.615,18.52,1,1,4,2,"Honda Civic"
21
+ 33.9,4,71.1,65,4.22,1.835,19.9,1,1,4,1,"Toyota Corolla"
22
+ 21.5,4,120.1,97,3.7,2.465,20.01,1,0,3,1,"Toyota Corona"
23
+ 15.5,8,318,150,2.76,3.52,16.87,0,0,3,2,"Dodge Challenger"
24
+ 15.2,8,304,150,3.15,3.435,17.3,0,0,3,2,"AMC Javelin"
25
+ 13.3,8,350,245,3.73,3.84,15.41,0,0,3,4,"Camaro Z28"
26
+ 19.2,8,400,175,3.08,3.845,17.05,0,0,3,2,"Pontiac Firebird"
27
+ 27.3,4,79,66,4.08,1.935,18.9,1,1,4,1,"Fiat X1-9"
28
+ 26,4,120.3,91,4.43,2.14,16.7,0,1,5,2,"Porsche 914-2"
29
+ 30.4,4,95.1,113,3.77,1.513,16.9,1,1,5,2,"Lotus Europa"
30
+ 15.8,8,351,264,4.22,3.17,14.5,0,1,5,4,"Ford Pantera L"
31
+ 19.7,6,145,175,3.62,2.77,15.5,0,1,5,6,"Ferrari Dino"
32
+ 15,8,301,335,3.54,3.57,14.6,0,1,5,8,"Maserati Bora"
33
+ 21.4,4,121,109,4.11,2.78,18.6,1,1,4,2,"Volvo 142E"