hfariborzi commited on
Commit
52d845e
ยท
verified ยท
1 Parent(s): 6d24d90

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +384 -31
src/streamlit_app.py CHANGED
@@ -1,3 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
  import os
2
  # On Huggingface Spaces the home directory may be unwritable; override it to the current working directory
3
  os.environ['HOME'] = os.getcwd()
@@ -8,35 +20,213 @@ import streamlit as st
8
  import pandas as pd
9
  import numpy as np
10
 
 
11
  def composite_correlations(R, composite_idx, var_names=None, augment=False):
12
- """Compute unit-weighted composite correlations."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  R_mat = np.asarray(R, dtype=float)
14
- n_all = R_mat.shape[0]
15
- n = len(composite_idx)
16
- # sub-matrix of the composite items
 
 
 
 
 
17
  R_yy = R_mat[np.ix_(composite_idx, composite_idx)]
18
- # mean off-diagonal
 
 
 
 
19
  iu = np.triu_indices(n, k=1)
 
 
 
 
20
  rbar = R_yy[iu].mean() if iu[0].size > 0 else 0.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  denom = np.sqrt(n + n*(n-1)*rbar)
 
 
 
 
 
 
 
 
 
 
 
 
22
  numer = R_mat[composite_idx, :].sum(axis=0)
 
 
 
 
 
 
 
 
 
 
 
23
  r_comp = numer / denom
24
 
 
25
  if var_names is not None:
26
  r_comp = pd.Series(r_comp, index=var_names, name="Composite")
27
 
 
28
  if not augment:
29
  return r_comp
30
 
31
- # build augmented matrix
 
 
 
 
32
  if var_names is not None:
 
33
  idx = list(var_names) + ["Composite"]
34
  R_aug = pd.DataFrame(np.zeros((n_all+1, n_all+1)), index=idx, columns=idx)
 
 
35
  R_aug.iloc[:-1, :-1] = R_mat
36
- R_aug.iloc[-1, :-1] = r_comp.values
37
- R_aug.iloc[:-1, -1] = r_comp.values
 
 
 
 
38
  R_aug.iloc[-1, -1] = 1.0
39
  else:
 
40
  R_aug = np.zeros((n_all+1, n_all+1))
41
  R_aug[:n_all, :n_all] = R_mat
42
  R_aug[n_all, :n_all] = r_comp
@@ -45,57 +235,220 @@ def composite_correlations(R, composite_idx, var_names=None, augment=False):
45
 
46
  return r_comp, R_aug
47
 
 
 
 
 
 
48
  # Streamlit UI
49
  st.title("Composite-Correlation Calculator")
 
50
  st.markdown("""
51
- Upload a CSV containing your (possibly lower-triangular) correlation matrix.
52
- The app will fill in missing cells by symmetry, set diagonals to 1,
53
- then let you select which variables go into a unit-weighted composite.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  """)
55
 
56
  uploaded = st.file_uploader("Upload correlation matrix (CSV)", type=["csv"])
 
57
  if uploaded is not None:
58
- # 1) read and label
59
  try:
60
  df = pd.read_csv(uploaded, index_col=0)
61
- except Exception:
62
- st.error("Failed to read CSV. Make sure the first column contains row labels.")
 
63
  st.stop()
 
 
64
  if df.shape[0] != df.shape[1]:
65
- st.error("Matrix must be square.")
66
  st.stop()
67
 
68
- st.success(f"Loaded a {df.shape[0]}ร—{df.shape[1]} matrix.")
69
 
70
- # 2) symmetrize and fill diagonal
 
 
71
  mat = df.values.astype(float)
72
- mat = np.where(np.isnan(mat), mat.T, mat) # fill missing by transpose
73
- np.fill_diagonal(mat, 1.0) # ensure diagonal = 1
 
74
  df_sym = pd.DataFrame(mat, index=df.index, columns=df.columns)
75
- st.write("**Symmetrized & filled diagonal:**")
76
- st.dataframe(df_sym)
 
77
 
78
- # 3) select composite variables
79
  all_vars = list(df_sym.columns)
 
 
 
 
80
  composite_vars = st.multiselect(
81
- "Select variables to form the composite",
82
  options=all_vars,
83
- default=all_vars[: min(3, len(all_vars))]
 
84
  )
 
85
  if len(composite_vars) < 2:
86
- st.warning("Pick at least 2 variables for a composite.")
87
  else:
88
- if st.button("Compute composite correlations"):
 
 
 
89
  idx = [all_vars.index(v) for v in composite_vars]
 
 
90
  r_comp, R_aug = composite_correlations(
91
  df_sym.values,
92
  composite_idx=idx,
93
  var_names=all_vars,
94
  augment=True
95
  )
96
- st.subheader("Composite vs. Each Variable")
97
- st.dataframe(r_comp.to_frame())
98
- st.subheader("Augmented Correlation Matrix")
99
- st.dataframe(R_aug)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  else:
101
- st.info("๐Ÿค– Upload a CSV file to get started.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ COMPOSITE CORRELATION CALCULATOR - COMPLETE EXPLANATION
3
+ ========================================================
4
+
5
+ This module implements unit-weighted composite correlation calculation from a correlation matrix.
6
+ It uses the classical test theory formula to compute correlations between a composite (sum of items)
7
+ and all other variables, without needing raw data.
8
+
9
+ Author: HubMeta Team
10
+ Date: February 2026
11
+ """
12
+
13
  import os
14
  # On Huggingface Spaces the home directory may be unwritable; override it to the current working directory
15
  os.environ['HOME'] = os.getcwd()
 
20
  import pandas as pd
21
  import numpy as np
22
 
23
+
24
  def composite_correlations(R, composite_idx, var_names=None, augment=False):
25
+ """
26
+ Compute unit-weighted composite correlations from a correlation matrix.
27
+
28
+ This function calculates the correlation between a composite variable (formed by
29
+ summing multiple items) and all other variables in the correlation matrix. The
30
+ calculation is based on classical test theory and uses the psychometric formula
31
+ for composite reliability.
32
+
33
+ Mathematical Background
34
+ -----------------------
35
+ For a unit-weighted composite Y = Xโ‚ + Xโ‚‚ + ... + Xโ‚–, the correlation between
36
+ Y and any variable Z is:
37
+
38
+ r(Y, Z) = ฮฃแตข r(Xแตข, Z) / ฯƒ_Y
39
+
40
+ where ฯƒ_Y = sqrt(k + k(k-1)ร—rฬ„)
41
+
42
+ Here:
43
+ - k = number of items in the composite
44
+ - rฬ„ = average inter-item correlation (mean of off-diagonal correlations in R_yy)
45
+ - ฮฃแตข r(Xแตข, Z) = sum of correlations between each composite item and variable Z
46
+
47
+ This formula is mathematically equivalent to:
48
+ 1. Creating composite scores by summing items
49
+ 2. Correlating the composite with each variable
50
+
51
+ But it works directly from the correlation matrix without needing raw data.
52
+
53
+ Parameters
54
+ ----------
55
+ R : array-like, shape (n_vars, n_vars)
56
+ Full correlation matrix. Can be a numpy array or pandas DataFrame.
57
+ Must be symmetric with 1s on the diagonal.
58
+
59
+ composite_idx : list of int
60
+ Indices of variables to include in the composite.
61
+ Example: [0, 2, 5] means use variables at positions 0, 2, and 5.
62
+
63
+ var_names : list of str, optional
64
+ Names of all variables in R. If provided, output will be a labeled Series.
65
+ Length must match R.shape[0].
66
+
67
+ augment : bool, default=False
68
+ If True, return both the composite correlations AND an augmented correlation
69
+ matrix that includes the composite as a new row/column.
70
+
71
+ Returns
72
+ -------
73
+ r_comp : array or Series
74
+ Correlations between the composite and each variable.
75
+ - If var_names is None: numpy array of shape (n_vars,)
76
+ - If var_names provided: pandas Series with variable names as index
77
+
78
+ R_aug : array or DataFrame (only if augment=True)
79
+ Augmented correlation matrix of shape (n_vars+1, n_vars+1) that includes
80
+ the composite as the last row/column.
81
+
82
+ Algorithm Steps
83
+ ---------------
84
+ 1. Extract R_yy: sub-matrix of correlations among composite items
85
+ 2. Calculate rฬ„: mean of off-diagonal correlations in R_yy
86
+ 3. Calculate denominator: ฯƒ_Y = sqrt(k + k(k-1)ร—rฬ„)
87
+ 4. Calculate numerator: for each variable, sum its correlations with all composite items
88
+ 5. Compute final correlation: r_comp = numerator / denominator
89
+
90
+ Examples
91
+ --------
92
+ >>> # Simple example with 5 variables
93
+ >>> R = np.array([
94
+ ... [1.0, 0.5, 0.6, 0.3, 0.4],
95
+ ... [0.5, 1.0, 0.7, 0.2, 0.3],
96
+ ... [0.6, 0.7, 1.0, 0.4, 0.5],
97
+ ... [0.3, 0.2, 0.4, 1.0, 0.8],
98
+ ... [0.4, 0.3, 0.5, 0.8, 1.0]
99
+ ... ])
100
+ >>>
101
+ >>> # Create composite from first 3 variables (indices 0, 1, 2)
102
+ >>> r_comp = composite_correlations(R, composite_idx=[0, 1, 2])
103
+ >>> print(r_comp)
104
+ [0.95 0.95 0.95 0.48 0.60] # Composite correlates highly with its items
105
+
106
+ >>> # With variable names and augmented matrix
107
+ >>> var_names = ['Item1', 'Item2', 'Item3', 'Outcome1', 'Outcome2']
108
+ >>> r_comp, R_aug = composite_correlations(
109
+ ... R, composite_idx=[0, 1, 2], var_names=var_names, augment=True
110
+ ... )
111
+ >>> print(r_comp)
112
+ Item1 0.95
113
+ Item2 0.95
114
+ Item3 0.95
115
+ Outcome1 0.48
116
+ Outcome2 0.60
117
+ Name: Composite, dtype: float64
118
+
119
+ Notes
120
+ -----
121
+ - The composite items will have correlations close to 1.0 with the composite
122
+ (exact value depends on inter-item correlations)
123
+ - This assumes unit weighting (all items weighted equally)
124
+ - For reliability-weighted composites, use a different formula
125
+ - The denominator adjustment accounts for the fact that composite variance
126
+ includes both item variances and covariances
127
+
128
+ References
129
+ ----------
130
+ - Nunnally, J. C., & Bernstein, I. H. (1994). Psychometric Theory (3rd ed.).
131
+ McGraw-Hill. Chapter 6: The Assessment of Reliability.
132
+ - Schmidt, F. L., & Hunter, J. E. (2015). Methods of Meta-Analysis (3rd ed.).
133
+ Sage Publications. Chapter 3: Correlational Artifacts.
134
+ """
135
+ # Convert input to numpy array (handles both arrays and DataFrames)
136
  R_mat = np.asarray(R, dtype=float)
137
+ n_all = R_mat.shape[0] # Total number of variables
138
+ n = len(composite_idx) # Number of items in composite
139
+
140
+ # STEP 1: Extract sub-matrix of correlations among composite items
141
+ # ----------------------------------------------------------------
142
+ # R_yy is the kร—k correlation matrix for just the composite items
143
+ # Example: if composite_idx = [0, 2, 5] and R is 10ร—10,
144
+ # R_yy will be the 3ร—3 matrix of correlations among variables 0, 2, 5
145
  R_yy = R_mat[np.ix_(composite_idx, composite_idx)]
146
+
147
+ # STEP 2: Calculate average inter-item correlation (rฬ„)
148
+ # -----------------------------------------------------
149
+ # Get upper triangle indices (excluding diagonal)
150
+ # For a 3ร—3 matrix, this gives positions: (0,1), (0,2), (1,2)
151
  iu = np.triu_indices(n, k=1)
152
+
153
+ # Extract off-diagonal correlations and compute mean
154
+ # This is the average correlation between items in the composite
155
+ # Example: if items correlate at [0.5, 0.6, 0.7], rbar = 0.6
156
  rbar = R_yy[iu].mean() if iu[0].size > 0 else 0.0
157
+
158
+ # STEP 3: Calculate denominator (composite standard deviation)
159
+ # ------------------------------------------------------------
160
+ # Formula: ฯƒ_Y = sqrt(k + k(k-1)ร—rฬ„)
161
+ #
162
+ # Derivation:
163
+ # For unit-weighted composite Y = Xโ‚ + Xโ‚‚ + ... + Xโ‚– (assuming standardized items):
164
+ # Var(Y) = Var(Xโ‚) + Var(Xโ‚‚) + ... + Var(Xโ‚–) + 2ร—ฮฃแตข<โฑผ Cov(Xแตข, Xโฑผ)
165
+ # = k + 2ร—ฮฃแตข<โฑผ r(Xแตข, Xโฑผ)
166
+ # = k + k(k-1)ร—rฬ„
167
+ #
168
+ # where we used: Var(Xแตข) = 1 (standardized)
169
+ # Cov(Xแตข, Xโฑผ) = r(Xแตข, Xโฑผ) (correlation = covariance for standardized vars)
170
+ # Number of pairs = k(k-1)/2, so 2ร—ฮฃแตข<โฑผ = k(k-1)ร—rฬ„
171
+ #
172
+ # Example: 3 items with rฬ„ = 0.6
173
+ # denom = sqrt(3 + 3ร—2ร—0.6) = sqrt(3 + 3.6) = sqrt(6.6) โ‰ˆ 2.57
174
  denom = np.sqrt(n + n*(n-1)*rbar)
175
+
176
+ # STEP 4: Calculate numerator (sum of correlations)
177
+ # -------------------------------------------------
178
+ # For each variable in the full matrix, sum its correlations with all composite items
179
+ #
180
+ # R_mat[composite_idx, :] extracts rows corresponding to composite items
181
+ # .sum(axis=0) sums down columns, giving sum of correlations for each variable
182
+ #
183
+ # Example: If composite has items [A, B, C] and we want correlation with variable X:
184
+ # numer[X] = r(A,X) + r(B,X) + r(C,X)
185
+ #
186
+ # This is vectorized - computes for all variables at once
187
  numer = R_mat[composite_idx, :].sum(axis=0)
188
+
189
+ # STEP 5: Compute final composite correlation
190
+ # -------------------------------------------
191
+ # r(Composite, X) = ฮฃแตข r(Xแตข, X) / ฯƒ_Y
192
+ #
193
+ # This divides the sum of item-X correlations by the composite's standard deviation
194
+ # The result is the correlation between the composite and each variable
195
+ #
196
+ # Interpretation:
197
+ # - Composite items will have r โ‰ˆ 0.9-1.0 (high correlation with their own composite)
198
+ # - Other variables will have r based on their average correlation with composite items
199
  r_comp = numer / denom
200
 
201
+ # Format output as pandas Series if variable names provided
202
  if var_names is not None:
203
  r_comp = pd.Series(r_comp, index=var_names, name="Composite")
204
 
205
+ # Return just correlations if augment=False
206
  if not augment:
207
  return r_comp
208
 
209
+ # STEP 6: Build augmented correlation matrix (optional)
210
+ # -----------------------------------------------------
211
+ # Create a new correlation matrix that includes the composite as a new variable
212
+ # This is useful for further analyses that need the composite in the matrix
213
+
214
  if var_names is not None:
215
+ # Create labeled DataFrame
216
  idx = list(var_names) + ["Composite"]
217
  R_aug = pd.DataFrame(np.zeros((n_all+1, n_all+1)), index=idx, columns=idx)
218
+
219
+ # Copy original matrix to top-left block
220
  R_aug.iloc[:-1, :-1] = R_mat
221
+
222
+ # Add composite correlations to last row and column
223
+ R_aug.iloc[-1, :-1] = r_comp.values # Last row (composite vs all vars)
224
+ R_aug.iloc[:-1, -1] = r_comp.values # Last column (all vars vs composite)
225
+
226
+ # Diagonal element (composite vs itself) = 1.0
227
  R_aug.iloc[-1, -1] = 1.0
228
  else:
229
+ # Create unlabeled array
230
  R_aug = np.zeros((n_all+1, n_all+1))
231
  R_aug[:n_all, :n_all] = R_mat
232
  R_aug[n_all, :n_all] = r_comp
 
235
 
236
  return r_comp, R_aug
237
 
238
+
239
+ # =============================================================================
240
+ # STREAMLIT WEB APPLICATION
241
+ # =============================================================================
242
+
243
  # Streamlit UI
244
  st.title("Composite-Correlation Calculator")
245
+
246
  st.markdown("""
247
+ ### What This Tool Does
248
+
249
+ This calculator computes **unit-weighted composite correlations** from a correlation matrix.
250
+
251
+ **Use Case:** You have a correlation matrix and want to:
252
+ 1. Combine multiple items into a composite score (e.g., sum of survey items)
253
+ 2. See how the composite correlates with other variables
254
+ 3. Add the composite to your correlation matrix for further analysis
255
+
256
+ **How It Works:**
257
+ - Upload a correlation matrix (CSV file)
258
+ - Select which variables form the composite
259
+ - Get correlations between the composite and all variables
260
+ - Optionally get an augmented matrix with the composite included
261
+
262
+ **Formula:** Uses the psychometric formula `r(Composite, X) = ฮฃr(item, X) / sqrt(k + k(k-1)ร—rฬ„)`
263
+
264
+ ---
265
+
266
+ ### Instructions
267
+
268
+ 1. **Upload a CSV file** containing your correlation matrix
269
+ - First column should contain row labels (variable names)
270
+ - Can be lower-triangular (missing values will be filled by symmetry)
271
+ - Diagonal values will be set to 1.0 if missing
272
+
273
+ 2. **Select variables** to include in the composite (minimum 2)
274
+
275
+ 3. **Click "Compute"** to see results
276
  """)
277
 
278
  uploaded = st.file_uploader("Upload correlation matrix (CSV)", type=["csv"])
279
+
280
  if uploaded is not None:
281
+ # 1) Read and label the correlation matrix
282
  try:
283
  df = pd.read_csv(uploaded, index_col=0)
284
+ except Exception as e:
285
+ st.error(f"Failed to read CSV: {e}")
286
+ st.info("Make sure the first column contains row labels (variable names).")
287
  st.stop()
288
+
289
+ # Validate square matrix
290
  if df.shape[0] != df.shape[1]:
291
+ st.error(f"Matrix must be square. Got {df.shape[0]} rows and {df.shape[1]} columns.")
292
  st.stop()
293
 
294
+ st.success(f"โœ… Loaded a {df.shape[0]}ร—{df.shape[1]} correlation matrix.")
295
 
296
+ # 2) Symmetrize and fill diagonal
297
+ # Many correlation matrices are stored as lower-triangular to save space
298
+ # This fills in the upper triangle by copying from the lower triangle
299
  mat = df.values.astype(float)
300
+ mat = np.where(np.isnan(mat), mat.T, mat) # Fill missing cells by transpose (symmetry)
301
+ np.fill_diagonal(mat, 1.0) # Ensure diagonal = 1.0 (self-correlation)
302
+
303
  df_sym = pd.DataFrame(mat, index=df.index, columns=df.columns)
304
+
305
+ with st.expander("๐Ÿ“Š View symmetrized correlation matrix"):
306
+ st.dataframe(df_sym.style.format("{:.3f}"))
307
 
308
+ # 3) Select composite variables
309
  all_vars = list(df_sym.columns)
310
+
311
+ st.subheader("Select Composite Items")
312
+ st.markdown("Choose which variables to combine into a unit-weighted composite:")
313
+
314
  composite_vars = st.multiselect(
315
+ "Variables in composite",
316
  options=all_vars,
317
+ default=all_vars[: min(3, len(all_vars))], # Default to first 3 variables
318
+ help="Select at least 2 variables to form a composite"
319
  )
320
+
321
  if len(composite_vars) < 2:
322
+ st.warning("โš ๏ธ Please select at least 2 variables to form a composite.")
323
  else:
324
+ st.info(f"Selected {len(composite_vars)} items for composite: {', '.join(composite_vars)}")
325
+
326
+ if st.button("๐Ÿงฎ Compute Composite Correlations", type="primary"):
327
+ # Get indices of selected variables
328
  idx = [all_vars.index(v) for v in composite_vars]
329
+
330
+ # Compute composite correlations with augmented matrix
331
  r_comp, R_aug = composite_correlations(
332
  df_sym.values,
333
  composite_idx=idx,
334
  var_names=all_vars,
335
  augment=True
336
  )
337
+
338
+ # Display results
339
+ st.success("โœ… Computation complete!")
340
+
341
+ # Show composite correlations
342
+ st.subheader("๐Ÿ“ˆ Composite Correlations")
343
+ st.markdown("""
344
+ These are the correlations between your composite (sum of selected items)
345
+ and each variable in the matrix.
346
+ """)
347
+
348
+ # Create a styled dataframe
349
+ result_df = r_comp.to_frame()
350
+ result_df.columns = ['Correlation with Composite']
351
+
352
+ # Highlight composite items
353
+ def highlight_composite(row):
354
+ if row.name in composite_vars:
355
+ return ['background-color: #e3f2fd'] * len(row)
356
+ return [''] * len(row)
357
+
358
+ st.dataframe(
359
+ result_df.style
360
+ .format("{:.4f}")
361
+ .apply(highlight_composite, axis=1)
362
+ .bar(subset=['Correlation with Composite'], color='#1f77b4', vmin=-1, vmax=1)
363
+ )
364
+
365
+ st.caption("๐Ÿ’ก Composite items (highlighted) typically have high correlations (0.8-1.0) with the composite.")
366
+
367
+ # Show augmented matrix
368
+ st.subheader("๐Ÿ“Š Augmented Correlation Matrix")
369
+ st.markdown("""
370
+ This matrix includes your composite as a new variable (last row/column).
371
+ You can use this for further analyses.
372
+ """)
373
+
374
+ with st.expander("View full augmented matrix"):
375
+ st.dataframe(R_aug.style.format("{:.3f}"))
376
+
377
+ # Download options
378
+ st.subheader("๐Ÿ’พ Download Results")
379
+
380
+ col1, col2 = st.columns(2)
381
+
382
+ with col1:
383
+ # Download composite correlations
384
+ csv1 = result_df.to_csv()
385
+ st.download_button(
386
+ label="Download Composite Correlations (CSV)",
387
+ data=csv1,
388
+ file_name="composite_correlations.csv",
389
+ mime="text/csv"
390
+ )
391
+
392
+ with col2:
393
+ # Download augmented matrix
394
+ csv2 = R_aug.to_csv()
395
+ st.download_button(
396
+ label="Download Augmented Matrix (CSV)",
397
+ data=csv2,
398
+ file_name="augmented_correlation_matrix.csv",
399
+ mime="text/csv"
400
+ )
401
+
402
+ # Show interpretation guide
403
+ with st.expander("๐Ÿ“– How to Interpret Results"):
404
+ st.markdown("""
405
+ **Composite Correlations:**
406
+ - **High (0.7-1.0):** Strong relationship with composite
407
+ - **Moderate (0.3-0.7):** Moderate relationship
408
+ - **Low (0.0-0.3):** Weak relationship
409
+ - **Negative:** Inverse relationship
410
+
411
+ **Composite Items:**
412
+ - Should correlate highly (0.8-1.0) with the composite
413
+ - Lower values suggest the item doesn't fit well
414
+ - Consider removing items with r < 0.7
415
+
416
+ **Other Variables:**
417
+ - Correlation shows how well they relate to the composite
418
+ - Use for criterion validity, predictive validity, etc.
419
+
420
+ **Formula Used:**
421
+ ```
422
+ r(Composite, X) = ฮฃr(item, X) / sqrt(k + k(k-1)ร—rฬ„)
423
+ ```
424
+ where k = number of items, rฬ„ = average inter-item correlation
425
+ """)
426
+
427
  else:
428
+ st.info("๐Ÿ‘† Upload a CSV file containing your correlation matrix to get started.")
429
+
430
+ # Show example
431
+ with st.expander("๐Ÿ“ Example CSV Format"):
432
+ st.markdown("""
433
+ Your CSV should look like this:
434
+
435
+ ```
436
+ ,Item1,Item2,Item3,Outcome1,Outcome2
437
+ Item1,1.0,0.5,0.6,0.3,0.4
438
+ Item2,0.5,1.0,0.7,0.2,0.3
439
+ Item3,0.6,0.7,1.0,0.4,0.5
440
+ Outcome1,0.3,0.2,0.4,1.0,0.8
441
+ Outcome2,0.4,0.3,0.5,0.8,1.0
442
+ ```
443
+
444
+ Or lower-triangular (missing values will be filled):
445
+
446
+ ```
447
+ ,Item1,Item2,Item3,Outcome1,Outcome2
448
+ Item1,1.0,,,,
449
+ Item2,0.5,1.0,,,
450
+ Item3,0.6,0.7,1.0,,
451
+ Outcome1,0.3,0.2,0.4,1.0,
452
+ Outcome2,0.4,0.3,0.5,0.8,1.0
453
+ ```
454
+ """)