45#include <gsl/gsl_statistics.h>
46#include <gsl/gsl_sort.h>
47#include <gsl/gsl_math.h>
53double bandwidth(
double data[], int64_t M);
54double gaussiankernelfunction(
double sample);
55double kerneldensityestimate(
double *trainingdata,
double sample, int64_t n,
double h);
56double *linearspace(
double initial,
double final,
int N);
67static char *option[N_OPTIONS] = {
74static const char *usage =
75 "sddskde [<inputfile>] [<outputfile>]\n"
76 " [-pipe=[input][,output]]\n"
77 " -column=<list of columns>\n"
78 " [-margin=<value>]\n"
79 " [-threads=<number>]\n"
81 "-column provide column names separated by commas, wild card accepted.\n"
82 "-margin provide the ratio to extend the original data, default 0.3.\n"
83 "-threads number of threads to use for PDF sample evaluation.\n"
84 "-pipe The standard SDDS Toolkit pipe option.\n\n"
85 "sddskde performs kernel density estimation for one-dimensional data.\n"
86 "Program by Yipeng Sun and Hairong Shang (" __DATE__
" " __TIME__
", SVN revision: " SVN_VERSION
").\n";
88int main(
int argc,
char **argv) {
90 double min_temp, max_temp;
91 double bwidth, gap, h, lower, upper;
94 char *input_file = NULL, *output_file = NULL, **column = NULL;
95 long tmpfile_used = 0, columns = 0, no_warnings = 1;
96 unsigned long pipe_flags;
99 double *column_data = NULL, *pdf = NULL, *cdf = NULL;
100 char buffer_pdf[1024], buffer_cdf[1024], buffer_pdf_units[1024];
105 argc =
scanargs(&s_arg, argc, argv);
109 fprintf(stderr,
"%s", usage);
113 for (i_arg = 1; i_arg < argc; i_arg++) {
114 if (s_arg[i_arg].arg_type == OPTION) {
116 switch (
match_string(s_arg[i_arg].list[0], option, N_OPTIONS, 0)) {
118 columns = s_arg[i_arg].n_items - 1;
119 column = realloc(column,
sizeof(*column) * columns);
120 for (i = 1; i < s_arg[i_arg].n_items; i++) {
121 column[i - 1] = s_arg[i_arg].list[i];
125 if (s_arg[i_arg].n_items != 2) {
128 if (!
get_double(&margin, s_arg[i_arg].list[1])) {
129 SDDS_Bomb(
"Invalid -margin value provided!");
133 if (s_arg[i_arg].n_items != 2 ||
134 sscanf(s_arg[i_arg].list[1],
"%d", &threads) != 1 || threads < 1) {
139 if (!
processPipeOption(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &pipe_flags)) {
140 fprintf(stderr,
"Error (%s): invalid -pipe syntax\n", argv[0]);
145 fprintf(stderr,
"Unknown option: %s\n", s_arg[i_arg].list[0]);
150 input_file = s_arg[i_arg].list[0];
151 }
else if (!output_file) {
152 output_file = s_arg[i_arg].list[0];
154 fprintf(stderr,
"Error (%s): too many filenames\n", argv[0]);
160 processFilenames(
"sddskde", &input_file, &output_file, pipe_flags, no_warnings, &tmpfile_used);
163 fprintf(stderr,
"%s", usage);
172 if ((columns = expandColumnPairNames(&sdds_in, &column, NULL, columns, NULL, 0, FIND_NUMERIC_TYPE, 0)) <= 0) {
181 for (i = 0; i < columns; i++) {
187 if (units && strlen(units)) {
188 snprintf(buffer_pdf_units,
sizeof(buffer_pdf_units),
"1/(%s)", units);
190 buffer_pdf_units[0] =
'\0';
195 snprintf(buffer_pdf,
sizeof(buffer_pdf),
"%sPDF", column[i]);
196 snprintf(buffer_cdf,
sizeof(buffer_cdf),
"%sCDF", column[i]);
209 pdf = malloc(
sizeof(*pdf) * n_test);
210 cdf = malloc(
sizeof(*cdf) * n_test);
218 for (i = 0; i < columns; i++) {
219 snprintf(buffer_pdf,
sizeof(buffer_pdf),
"%sPDF", column[i]);
220 snprintf(buffer_cdf,
sizeof(buffer_cdf),
"%sCDF", column[i]);
227 gap = max_temp - min_temp;
228 lower = min_temp - gap * margin;
229 upper = max_temp + gap * margin;
231 double *x_array = linearspace(lower, upper, n_test);
232 bwidth = bandwidth(column_data, rows);
233 h = GSL_MAX(bwidth, 2e-6);
235#pragma omp parallel for if (threads > 1) num_threads(threads)
236 for (j = 0; j < n_test; j++) {
237 pdf[j] = kerneldensityestimate(column_data, x_array[j], rows, h);
241 for (j = 1; j < n_test; j++) {
242 cdf[j] += cdf[j - 1];
245 for (j = 0; j < n_test; j++) {
246 cdf[j] = cdf[j] / cdf[n_test - 1];
284double bandwidth(
double data[], int64_t M) {
285 double sigma, min_val, bwidth, interquartile_range;
286 double hspread_three, hspread_one;
288 gsl_sort(data, 1, M);
289 sigma = gsl_stats_sd(data, 1, M);
290 hspread_three = gsl_stats_quantile_from_sorted_data(data, 1, M, 0.750);
291 hspread_one = gsl_stats_quantile_from_sorted_data(data, 1, M, 0.250);
292 interquartile_range = hspread_three - hspread_one;
293 min_val = GSL_MIN(interquartile_range / 1.339999, sigma);
294 bwidth = 0.90 * min_val * pow(M, -0.20);
299double gaussiankernelfunction(
double sample) {
301 k = exp(-(gsl_pow_2(sample) / 2.0));
302 k = k / (M_SQRT2 * sqrt(M_PI));
307double kerneldensityestimate(
double *trainingdata,
double sample, int64_t n,
double h) {
311 for (i = 0; i < n; i++) {
312 pdf += gaussiankernelfunction((trainingdata[i] - sample) / h);
320double *linearspace(
double start,
double end,
int N) {
325 x = calloc(N,
sizeof(
double));
326 step = (end - start) / (
double)(N - 1);
329 for (i = 1; i < N; i++) {
330 x[i] = x[i - 1] + step;
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_StartPage(SDDS_DATASET *SDDS_dataset, int64_t expected_n_rows)
int32_t SDDS_SetColumnFromDoubles(SDDS_DATASET *SDDS_dataset, int32_t mode, double *data, int64_t rows,...)
Sets the values for a single data column using double-precision floating-point numbers.
int32_t SDDS_GetColumnInformation(SDDS_DATASET *SDDS_dataset, char *field_name, void *memory, int32_t mode,...)
Retrieves information about a specified column in the SDDS dataset.
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_TransferColumnDefinition(SDDS_DATASET *target, SDDS_DATASET *source, char *name, char *newName)
Transfers a column definition from a source dataset to a target dataset.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
#define SDDS_STRING
Identifier for the string data type.
#define SDDS_DOUBLE
Identifier for the double data type.
Utility functions for SDDS dataset manipulation and string array operations.
int get_double(double *dptr, char *s)
Parses a double value from the given string.
char * delete_chars(char *s, char *t)
Removes all occurrences of characters found in string t from string s.
int find_min_max(double *min, double *max, double *list, int64_t n)
Finds the minimum and maximum values in a list of doubles.
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.
long replaceFileAndBackUp(char *file, char *replacement)
Replaces a file with a replacement file and creates a backup of the original.
int scanargs(SCANNED_ARG **scanned, int argc, char **argv)
long processPipeOption(char **item, long items, unsigned long *flags)
void processFilenames(char *programName, char **input, char **output, unsigned long pipeFlags, long noWarnings, long *tmpOutputUsed)