SDDS ToolKit Programs and Libraries for C and Python
Loading...
Searching...
No Matches
sddscorrelate.c File Reference

Detailed Description

Computes and evaluates correlations among columns of data in SDDS files.

This program reads an input SDDS file, calculates the correlation coefficients between specified or all numeric columns, and outputs the results to a new SDDS file. It supports options for rank-order correlation, standard deviation-based outlier removal, and column/row major data ordering.

Usage

sddscorrelate [<inputfile>] [<outputfile>]
[-pipe=[input][,output]]
[-columns=<list-of-names>]
[-excludeColumns=<list-of-names>]
[-withOnly=<name>]
[-rankOrder]
[-stDevOutlier[=limit=<factor>][,passes=<integer>]]
[-majorOrder=row|column]
[-threads=<number>]

Options

Option Description
-pipe Use standard input/output for input/output.
-columns Specify columns to include in correlation analysis.
-excludeColumns Specify columns to exclude from analysis.
-withOnly Correlate only with the specified column.
-rankOrder Use rank-order (Spearman) correlation instead of linear (Pearson).
-stDevOutlier Remove outliers based on standard deviation.
-majorOrder Set data ordering to row-major or column-major.
-threads Set the number of threads for rank and correlation computation.

Incompatibilities

  • -columns and -excludeColumns cannot be used together.
  • -withOnly is mutually exclusive with -excludeColumns.

Features

  • Linear (Pearson) or Rank-Order (Spearman) correlation calculation.
  • Exclusion of specific columns or correlation with a single column.
  • Outlier detection and removal using standard deviation thresholds.
  • Customizable data ordering (row-major or column-major).

Output

The output SDDS file contains:

  • Correlation coefficients and significance for column pairs.
  • Number of points used in the correlation.
  • Parameters summarizing the correlation analysis.
License
This file is distributed under the terms of the Software License Agreement found in the file LICENSE included with this distribution.
Author
M. Borland, C. Saunders, R. Soliday

Definition in file sddscorrelate.c.

#include "mdb.h"
#include "SDDS.h"
#include "scan.h"
#include "SDDSutils.h"
#include <ctype.h>

Go to the source code of this file.

Functions

void replaceWithRank (double *data, int64_t n)
 
double * findRank (double *data, int64_t n)
 
void markStDevOutliers (double *data, double limit, long passes, short *keep, int64_t n)
 
static long correlationPairIndex (long i, long j, long columns)
 
int main (int argc, char **argv)
 
int compareData (const void *d1, const void *d2)
 

Function Documentation

◆ compareData()

int compareData ( const void * d1,
const void * d2 )

Definition at line 450 of file sddscorrelate.c.

450 {
451 double diff = ((DATAnINDEX *)d1)->data - ((DATAnINDEX *)d2)->data;
452 if (diff < 0)
453 return -1;
454 else if (diff > 0)
455 return 1;
456 else
457 return 0;
458}

◆ correlationPairIndex()

static long correlationPairIndex ( long i,
long j,
long columns )
static

Definition at line 403 of file sddscorrelate.c.

403 {
404 return i * (2 * columns - i - 1) / 2 + (j - i - 1);
405}

◆ findRank()

double * findRank ( double * data,
int64_t n )

Definition at line 460 of file sddscorrelate.c.

460 {
461 double *rank = malloc(sizeof(*rank) * n);
462 if (!rank)
463 return NULL;
464 for (int64_t i = 0; i < n; i++)
465 rank[i] = data[i];
466 replaceWithRank(rank, n);
467 return rank;
468}

◆ main()

int main ( int argc,
char ** argv )

Definition at line 124 of file sddscorrelate.c.

124 {
125 int iArg;
126 char **column, **excludeColumn, *withOnly;
127 long columns, excludeColumns;
128 char *input, *output;
129 SCANNED_ARG *scanned;
130 SDDS_DATASET SDDSin, SDDSout;
131 long i, j, row, readCode, rankOrder, iName1, iName2;
132 long pairCount, pairIndex;
133 int64_t rows;
134 int32_t outlierStDevPasses;
135 double **data, outlierStDevLimit;
136 double *correlationValue, *significanceValue;
137 long *correlationPoints;
138 double **rank;
139 short **accept;
140 char s[SDDS_MAXLINE];
141 unsigned long pipeFlags, dummyFlags, majorOrderFlag;
142 short columnMajorOrder = -1;
143 int threads = 1;
144
146 argc = scanargs(&scanned, argc, argv);
147 if (argc < 2)
148 bomb(NULL, USAGE);
149
150 output = input = withOnly = NULL;
151 columns = excludeColumns = 0;
152 column = excludeColumn = NULL;
153 pipeFlags = 0;
154 rankOrder = 0;
155 outlierStDevPasses = 0;
156 outlierStDevLimit = 1.0;
157 rank = NULL;
158 accept = NULL;
159
160 for (iArg = 1; iArg < argc; iArg++) {
161 if (scanned[iArg].arg_type == OPTION) {
162 /* process options here */
163 switch (match_string(scanned[iArg].list[0], option, N_OPTIONS, 0)) {
164 case SET_MAJOR_ORDER:
165 majorOrderFlag = 0;
166 scanned[iArg].n_items--;
167 if (scanned[iArg].n_items > 0 &&
168 (!scanItemList(&majorOrderFlag, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
169 "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
170 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)))
171 SDDS_Bomb("invalid -majorOrder syntax/values");
172 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
173 columnMajorOrder = 1;
174 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
175 columnMajorOrder = 0;
176 break;
177 case SET_COLUMNS:
178 if (columns)
179 SDDS_Bomb("only one -columns option may be given");
180 if (scanned[iArg].n_items < 2)
181 SDDS_Bomb("invalid -columns syntax");
182 column = tmalloc(sizeof(*column) * (columns = scanned[iArg].n_items - 1));
183 for (i = 0; i < columns; i++)
184 column[i] = scanned[iArg].list[i + 1];
185 break;
186 case SET_EXCLUDE:
187 if (scanned[iArg].n_items < 2)
188 SDDS_Bomb("invalid -excludeColumns syntax");
189 moveToStringArray(&excludeColumn, &excludeColumns, scanned[iArg].list + 1, scanned[iArg].n_items - 1);
190 break;
191 case SET_WITHONLY:
192 if (withOnly)
193 SDDS_Bomb("only one -withOnly option may be given");
194 if (scanned[iArg].n_items < 2)
195 SDDS_Bomb("invalid -withOnly syntax");
196 withOnly = scanned[iArg].list[1];
197 break;
198 case SET_PIPE:
199 if (!processPipeOption(scanned[iArg].list + 1, scanned[iArg].n_items - 1, &pipeFlags))
200 SDDS_Bomb("invalid -pipe syntax");
201 break;
202 case SET_RANKORDER:
203 rankOrder = 1;
204 break;
205 case SET_STDEVOUTLIER:
206 scanned[iArg].n_items--;
207 outlierStDevPasses = 1;
208 outlierStDevLimit = 1.0;
209 if (!scanItemList(&dummyFlags, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
210 "limit", SDDS_DOUBLE, &outlierStDevLimit, 1, 0,
211 "passes", SDDS_LONG, &outlierStDevPasses, 1, 0, NULL) ||
212 outlierStDevPasses <= 0 || outlierStDevLimit <= 0.0)
213 SDDS_Bomb("invalid -stdevOutlier syntax/values");
214 break;
215 case SET_THREADS:
216 if (scanned[iArg].n_items != 2 ||
217 sscanf(scanned[iArg].list[1], "%d", &threads) != 1 || threads < 1)
218 SDDS_Bomb("invalid -threads syntax");
219 break;
220 default:
221 fprintf(stderr, "Error: unknown or ambiguous option: %s\n", scanned[iArg].list[0]);
222 exit(EXIT_FAILURE);
223 break;
224 }
225 } else {
226 if (!input)
227 input = scanned[iArg].list[0];
228 else if (!output)
229 output = scanned[iArg].list[0];
230 else
231 SDDS_Bomb("too many filenames seen");
232 }
233 }
234
235 processFilenames("sddscorrelate", &input, &output, pipeFlags, 0, NULL);
236
237 if (!SDDS_InitializeInput(&SDDSin, input))
238 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
239
240 if (!columns)
241 columns = appendToStringArray(&column, columns, "*");
242 if (withOnly)
243 columns = appendToStringArray(&column, columns, withOnly);
244
245 if ((columns = expandColumnPairNames(&SDDSin, &column, NULL, columns, excludeColumn, excludeColumns, FIND_NUMERIC_TYPE, 0)) <= 0) {
246 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
247 SDDS_Bomb("no columns selected for correlation analysis");
248 }
249
250 if (!SDDS_InitializeOutput(&SDDSout, SDDS_BINARY, 0, NULL, "sddscorrelate output", output) ||
251 SDDS_DefineColumn(&SDDSout, "Correlate1Name", NULL, NULL, "Name of correlated quantity 1", NULL, SDDS_STRING, 0) < 0 ||
252 SDDS_DefineColumn(&SDDSout, "Correlate2Name", NULL, NULL, "Name of correlated quantity 2", NULL, SDDS_STRING, 0) < 0 ||
253 SDDS_DefineColumn(&SDDSout, "CorrelatePair", NULL, NULL, "Names of correlated quantities", NULL, SDDS_STRING, 0) < 0 ||
254 SDDS_DefineColumn(&SDDSout, "CorrelationCoefficient", "r", NULL, "Linear correlation coefficient", NULL, SDDS_DOUBLE, 0) < 0 ||
255 SDDS_DefineColumn(&SDDSout, "CorrelationSignificance", "P$br$n", NULL, "Linear correlation coefficient significance", NULL, SDDS_DOUBLE, 0) < 0 ||
256 SDDS_DefineColumn(&SDDSout, "CorrelationPoints", NULL, NULL, "Number of points used for correlation", NULL, SDDS_LONG, 0) < 0 ||
257 SDDS_DefineParameter(&SDDSout, "CorrelatedRows", NULL, NULL, "Number of data rows in correlation analysis", NULL, SDDS_LONG, NULL) < 0 ||
258 SDDS_DefineParameter(&SDDSout, "sddscorrelateInputFile", NULL, NULL, "Data file processed by sddscorrelate", NULL, SDDS_STRING, input ? input : "stdin") < 0 ||
259 SDDS_DefineParameter(&SDDSout, "sddscorrelateMode", NULL, NULL, NULL, NULL, SDDS_STRING, rankOrder ? "Rank-Order (Spearman)" : "Linear (Pearson)") < 0 ||
260 SDDS_DefineParameter1(&SDDSout, "sddscorrelateStDevOutlierPasses", NULL, NULL, "Number of passes of standard-deviation outlier elimination applied", NULL, SDDS_LONG, &outlierStDevPasses) < 0 ||
261 SDDS_DefineParameter1(&SDDSout, "sddscorrelateStDevOutlierLimit", NULL, NULL, "Standard-deviation outlier limit applied", NULL, SDDS_DOUBLE, &outlierStDevLimit) < 0) {
262 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
263 }
264
265 if (columnMajorOrder != -1)
266 SDDSout.layout.data_mode.column_major = columnMajorOrder;
267 else
268 SDDSout.layout.data_mode.column_major = SDDSin.layout.data_mode.column_major;
269
270 if (!SDDS_WriteLayout(&SDDSout))
271 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
272
273 data = malloc(sizeof(*data) * columns);
274 pairCount = columns * (columns - 1) / 2;
275 correlationValue = pairCount ? malloc(sizeof(*correlationValue) * pairCount) : NULL;
276 significanceValue = pairCount ? malloc(sizeof(*significanceValue) * pairCount) : NULL;
277 correlationPoints = pairCount ? malloc(sizeof(*correlationPoints) * pairCount) : NULL;
278 if (!data ||
279 (pairCount && (!correlationValue || !significanceValue || !correlationPoints)) ||
280 (rankOrder && !(rank = malloc(sizeof(*rank) * columns))) ||
281 !(accept = malloc(sizeof(*accept) * columns))) {
282 SDDS_Bomb("allocation failure");
283 }
284
285 while ((readCode = SDDS_ReadPage(&SDDSin)) > 0) {
286 if ((rows = SDDS_CountRowsOfInterest(&SDDSin)) < 3)
287 continue;
288 if (!SDDS_StartPage(&SDDSout, columns * (columns - 1) / 2) ||
289 !SDDS_SetParameters(&SDDSout, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, "CorrelatedRows", rows, NULL)) {
290 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
291 }
292 for (i = 0; i < columns; i++) {
293 data[i] = SDDS_GetColumnInDoubles(&SDDSin, column[i]);
294 if (!data[i])
295 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
296 if (rankOrder)
297 rank[i] = NULL;
298 accept[i] = NULL;
299 if (outlierStDevPasses) {
300 accept[i] = malloc(sizeof(**accept) * rows);
301 if (!accept[i])
302 SDDS_Bomb("allocation failure");
303 }
304 }
305#pragma omp parallel for if (threads > 1) num_threads(threads)
306 for (i = 0; i < columns; i++) {
307 if (rankOrder)
308 rank[i] = findRank(data[i], rows);
309 if (outlierStDevPasses)
310 markStDevOutliers(data[i], outlierStDevLimit, outlierStDevPasses, accept[i], rows);
311 }
312#pragma omp parallel for private(j, iName1, iName2, pairIndex) if (threads > 1) num_threads(threads)
313 for (i = 0; i < columns; i++) {
314 for (j = i + 1; j < columns; j++) {
315 long count;
316 double correlation, significance;
317 pairIndex = correlationPairIndex(i, j, columns);
318 iName1 = i;
319 iName2 = j;
320 if (withOnly) {
321 if (strcmp(withOnly, column[i]) == 0) {
322 iName1 = j;
323 iName2 = i;
324 } else if (strcmp(withOnly, column[j]) == 0) {
325 iName1 = i;
326 iName2 = j;
327 } else {
328 correlationValue[pairIndex] = 0;
329 significanceValue[pairIndex] = 0;
330 correlationPoints[pairIndex] = 0;
331 continue;
332 }
333 }
334 correlation = linearCorrelationCoefficient(rankOrder ? rank[i] : data[i],
335 rankOrder ? rank[j] : data[j],
336 accept[i], accept[j], rows, &count);
337 significance = linearCorrelationSignificance(correlation, count);
338 correlationValue[pairIndex] = correlation;
339 significanceValue[pairIndex] = significance;
340 correlationPoints[pairIndex] = count;
341 }
342 }
343 for (i = row = 0; i < columns; i++) {
344 for (j = i + 1; j < columns; j++) {
345 pairIndex = correlationPairIndex(i, j, columns);
346 iName1 = i;
347 iName2 = j;
348 if (withOnly) {
349 if (strcmp(withOnly, column[i]) == 0) {
350 iName1 = j;
351 iName2 = i;
352 } else if (strcmp(withOnly, column[j]) == 0) {
353 iName1 = i;
354 iName2 = j;
355 } else {
356 continue;
357 }
358 }
359 snprintf(s, sizeof(s), "%s.%s", column[iName1], column[iName2]);
360 if (!SDDS_SetRowValues(&SDDSout, SDDS_SET_BY_INDEX | SDDS_PASS_BY_VALUE, row++,
361 0, column[iName1],
362 1, column[iName2],
363 2, s,
364 3, correlationValue[pairIndex],
365 4, significanceValue[pairIndex],
366 5, correlationPoints[pairIndex],
367 -1)) {
368 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
369 }
370 }
371 }
372 for (i = 0; i < columns; i++) {
373 free(data[i]);
374 if (rankOrder)
375 free(rank[i]);
376 if (accept[i])
377 free(accept[i]);
378 }
379 if (!SDDS_WritePage(&SDDSout))
380 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
381 }
382
383 free(data);
384 free(correlationValue);
385 free(significanceValue);
386 free(correlationPoints);
387 if (rankOrder)
388 free(rank);
389 free(accept);
390
391 if (!SDDS_Terminate(&SDDSin)) {
392 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
393 exit(EXIT_FAILURE);
394 }
395 if (!SDDS_Terminate(&SDDSout)) {
396 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
397 exit(EXIT_FAILURE);
398 }
399
400 return EXIT_SUCCESS;
401}
int32_t SDDS_SetRowValues(SDDS_DATASET *SDDS_dataset, int32_t mode, int64_t row,...)
int32_t SDDS_StartPage(SDDS_DATASET *SDDS_dataset, int64_t expected_n_rows)
int32_t SDDS_SetParameters(SDDS_DATASET *SDDS_dataset, int32_t mode,...)
int64_t SDDS_CountRowsOfInterest(SDDS_DATASET *SDDS_dataset)
Counts the number of rows marked as "of interest" in the current data table.
double * SDDS_GetColumnInDoubles(SDDS_DATASET *SDDS_dataset, char *column_name)
Retrieves the data of a specified numerical column as an array of doubles, considering only rows mark...
int32_t SDDS_InitializeInput(SDDS_DATASET *SDDS_dataset, char *filename)
Definition SDDS_input.c:50
int32_t SDDS_Terminate(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_ReadPage(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_DefineParameter1(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, void *fixed_value)
Defines a data parameter with a fixed numerical value.
int32_t SDDS_InitializeOutput(SDDS_DATASET *SDDS_dataset, int32_t data_mode, int32_t lines_per_row, const char *description, const char *contents, const char *filename)
Initializes the SDDS output dataset.
int32_t SDDS_WritePage(SDDS_DATASET *SDDS_dataset)
Writes the current data table to the output file.
int32_t SDDS_DefineColumn(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, int32_t field_length)
Defines a data column within the SDDS dataset.
int32_t SDDS_WriteLayout(SDDS_DATASET *SDDS_dataset)
Writes the SDDS layout header to the output file.
int32_t SDDS_DefineParameter(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, char *fixed_value)
Defines a data parameter with a fixed string value.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
Definition SDDS_utils.c:474
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
Definition SDDS_utils.c:318
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
Definition SDDS_utils.c:380
#define SDDS_STRING
Identifier for the string data type.
Definition SDDStypes.h:85
#define SDDS_LONG
Identifier for the signed 32-bit integer data type.
Definition SDDStypes.h:61
#define SDDS_DOUBLE
Identifier for the double data type.
Definition SDDStypes.h:37
void * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
Definition array.c:65
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
Definition bomb.c:26
double linearCorrelationSignificance(double r, long rows)
Compute the statistical significance of a linear correlation coefficient.
Definition lincorr.c:79
double linearCorrelationCoefficient(double *data1, double *data2, short *accept1, short *accept2, long rows, long *count)
Compute the linear correlation coefficient for two data sets.
Definition lincorr.c:32
long match_string(char *string, char **option, long n_options, long mode)
Matches a given string against an array of option strings based on specified modes.
int scanargs(SCANNED_ARG **scanned, int argc, char **argv)
Definition scanargs.c:36
long processPipeOption(char **item, long items, unsigned long *flags)
Definition scanargs.c:357
void processFilenames(char *programName, char **input, char **output, unsigned long pipeFlags, long noWarnings, long *tmpOutputUsed)
Definition scanargs.c:391
long scanItemList(unsigned long *flags, char **item, long *items, unsigned long mode,...)
Scans a list of items and assigns values based on provided keywords and types.

◆ markStDevOutliers()

void markStDevOutliers ( double * data,
double limit,
long passes,
short * keep,
int64_t n )

Definition at line 407 of file sddscorrelate.c.

407 {
408 double sum1, sum2, variance, mean, absLimit;
409 long pass;
410 int64_t i, summed, kept;
411
412 for (i = 0; i < n; i++)
413 keep[i] = 1;
414 kept = n;
415 for (pass = 0; pass < passes && kept; pass++) {
416 sum1 = 0.0;
417 summed = 0;
418 for (i = 0; i < n; i++) {
419 if (keep[i]) {
420 sum1 += data[i];
421 summed += 1;
422 }
423 }
424 if (summed < 2)
425 return;
426 mean = sum1 / summed;
427 sum2 = 0.0;
428 for (i = 0; i < n; i++) {
429 if (keep[i])
430 sum2 += sqr(data[i] - mean);
431 }
432 variance = sum2 / summed;
433 if (variance > 0.0) {
434 absLimit = limit * sqrt(variance);
435 for (i = 0; i < n; i++) {
436 if (keep[i] && fabs(data[i] - mean) > absLimit) {
437 keep[i] = 0;
438 kept--;
439 }
440 }
441 }
442 }
443}

◆ replaceWithRank()

void replaceWithRank ( double * data,
int64_t n )

Definition at line 470 of file sddscorrelate.c.

470 {
471 DATAnINDEX *indexedData = NULL;
472 int64_t i, j, iStart, iEnd;
473
474 indexedData = SDDS_Malloc(sizeof(*indexedData) * n);
475 for (i = 0; i < n; i++) {
476 indexedData[i].data = data[i];
477 indexedData[i].originalIndex = i;
478 }
479 qsort(indexedData, n, sizeof(*indexedData), compareData);
480 for (i = 0; i < n; i++)
481 data[indexedData[i].originalIndex] = (double)i;
482 for (i = 0; i < n - 1; i++) {
483 if (data[i] == data[i + 1]) {
484 iStart = i;
485 for (j = i + 2; j < n; j++) {
486 if (data[j] != data[i])
487 break;
488 }
489 iEnd = j - 1;
490 double averageRank = (iStart + iEnd) / 2.0;
491 for (j = iStart; j <= iEnd; j++)
492 data[indexedData[j].originalIndex] = averageRank;
493 i = iEnd;
494 }
495 }
496 free(indexedData);
497}
void * SDDS_Malloc(size_t size)
Allocates memory of a specified size.
Definition SDDS_utils.c:705