{"id":13878400,"url":"https://github.com/ankane/khiva-ruby","last_synced_at":"2025-08-31T03:31:39.845Z","repository":{"id":66166541,"uuid":"322436134","full_name":"ankane/khiva-ruby","owner":"ankane","description":"High-performance time series algorithms for Ruby","archived":true,"fork":false,"pushed_at":"2024-10-23T04:00:50.000Z","size":89,"stargazers_count":37,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-08-21T05:04:20.171Z","etag":null,"topics":["anomaly-detection","matrix-profile","stomp","time-series"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ankane.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-12-17T23:21:44.000Z","updated_at":"2024-11-23T06:47:25.000Z","dependencies_parsed_at":"2023-12-26T21:51:18.928Z","dependency_job_id":null,"html_url":"https://github.com/ankane/khiva-ruby","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/ankane/khiva-ruby","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ankane%2Fkhiva-ruby","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ankane%2Fkhiva-ruby/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ankane%2Fkhiva-ruby/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ankane%2Fkhiva-ruby/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ankane","download_url":"https://codeload.github.com/ankane/khiva-ruby/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ankane%2Fkhiva-ruby/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272934196,"owners_count":25017812,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-31T02:00:09.071Z","response_time":79,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["anomaly-detection","matrix-profile","stomp","time-series"],"created_at":"2024-08-06T08:01:48.494Z","updated_at":"2025-08-31T03:31:39.553Z","avatar_url":"https://github.com/ankane.png","language":"Ruby","funding_links":[],"categories":["Ruby"],"sub_categories":[],"readme":"# Khiva Ruby\n\n[Khiva](https://github.com/shapelets/khiva) - high-performance time series algorithms - for Ruby\n\n:fire: Runs on GPUs (even on Mac) and CPUs\n\n[![Build Status](https://github.com/ankane/khiva-ruby/actions/workflows/build.yml/badge.svg)](https://github.com/ankane/khiva-ruby/actions)\n\n## Installation\n\nFirst, [install Khiva](#khiva-installation). For Homebrew, use:\n\n```sh\nbrew install khiva\n```\n\nAdd this line to your application’s Gemfile:\n\n```ruby\ngem \"khiva\"\n```\n\n## Getting Started\n\nCalculate the [matrix profile](https://stumpy.readthedocs.io/en/latest/Tutorial_The_Matrix_Profile.html) between two time series\n\n```ruby\na = Khiva::Array.new([11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11], type: :f32)\nb = Khiva::Array.new([9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9], type: :f32)\nm = 3 # subsequence length\nprofile, index = Khiva::Matrix.stomp(a, b, m)\n```\n\nFind motifs (repeated patterns)\n\n```ruby\nn = 2 # number of motifs to extract\ndistances, indices, subsequences = Khiva::Matrix.find_best_n_motifs(profile, index, m, n)\n```\n\nFind discords (anomalies)\n\n```ruby\nn = 2 # number of discords to extract\ndistances, indices, subsequences = Khiva::Matrix.find_best_n_discords(profile, index, m, n)\n```\n\n## Examples\n\n- [Anomaly Detection](#anomaly-detection)\n- [Similarity Search](#similarity-search)\n\n### Anomaly Detection\n\nDetect anomalies in a time series\n\n```ruby\n# generate a random time series with anomalies from position 100-109\nseries = 1000.times.map { |i| i \u003e= 100 \u0026\u0026 i \u003c= 109 ? 0.5 : rand }\n\n# calculate the matrix profile with subsequence length 10\na = Khiva::Array.new(series, type: :f32)\nm = 10\nprofile, index = Khiva::Matrix.stomp_self_join(a, m)\n\n# find and print the position of the most anomalous subsequence\n_, _, subsequences = Khiva::Matrix.find_best_n_discords(profile, index, m, 1)\npos = subsequences.to_a.first\np pos\n```\n\nUse [matplotlib.rb](https://github.com/mrkn/matplotlib.rb) for visualization\n\n```ruby\nrequire \"matplotlib/pyplot\"\nplt = Matplotlib::Pyplot\n\n# series\nplt.figure(0)\nplt.title(\"Series\")\nplt.plot(series)\n\n# matrix profile\nplt.figure(1)\nplt.title(\"Matrix Profile\")\nplt.plot(profile.to_a)\n\n# most anomalous subsequence and its closest subsequence\nplt.figure(2)\nplt.title(\"Subsequences\")\nplt.plot(series[pos, m], label: \"Anomalous\")\nplt.plot(series[index.to_a[pos], m], label: \"Closest\")\nplt.legend\n```\n\n### Similarity Search\n\nFind a similar pattern in time series\n\n```ruby\nseries = [1, 1, 1, 3, 4, 1, 1, 1, 1]\nquery = [1, 2, 3]\n\ns = Khiva::Array.new(series, type: :f32)\nq = Khiva::Array.new(query, type: :f32)\n_, indices = Khiva::Matrix.find_best_n_occurrences(q, s, 1)\npos = indices.to_a.first\nsimilar_subsequence = series[pos, query.size] # [1, 3, 4]\n```\n\n## Modules\n\n- [Array](#array)\n- [Clustering](#clustering)\n- [Dimensionality](#dimensionality)\n- [Distances](#distances)\n- [Features](#features)\n- [Library](#library)\n- [Linalg](#linalg)\n- [Matrix](#matrix)\n- [Normalization](#normalization)\n- [Polynomial](#polynomial)\n- [Regression](#regression)\n- [Regularization](#regularization)\n- [Statistics](#statistics)\n\n## Array\n\nCreate an array from a Ruby array\n\n```ruby\nKhiva::Array.new([1, 2, 3])\n```\n\nSpecify the type - `:b8`, `:f32`, `:f64`, `:s16`, `:s32`, `:s64`, `:u8`, `:u16`, `:u32`, `:u64`\n\n```ruby\nKhiva::Array.new([1, 2, 3], type: :s64)\n```\n\nGet the type and dimensions\n\n```ruby\na.type\na.dims\n```\n\nPerform operations on arrays\n\n```ruby\na + b\na - b\na * b\na / b\na % b\na ** b\n```\n\nCompare arrays\n\n```ruby\na.eq(b)\na.ne(b)\na.lt(b)\na.gt(b)\na.le(b)\na.ge(b)\n```\n\n## Clustering\n\nk-means algorithm\n\n```ruby\ncentroids, labels = Khiva::Clustering.k_means(tss, k)\n```\n\nk-Shape algorithm\n\n```ruby\ncentroids, labels = Khiva::Clustering.k_shape(tss, k)\n```\n\n## Dimensionality\n\nPiecewise Aggregate Approximation (PAA)\n\n```ruby\nKhiva::Dimensionality.paa(a, bins)\n```\n\nPerceptually Important Points (PIP)\n\n```ruby\nKhiva::Dimensionality.pip(a, number_ips)\n```\n\nPiecewise Linear Approximation (PLA Bottom Up)\n\n```ruby\nKhiva::Dimensionality.pla_bottom_up(a, max_error)\n```\n\nPiecewise Linear Approximation (PLA Sliding Window)\n\n```ruby\nKhiva::Dimensionality.pla_sliding_window(a, max_error)\n```\n\nRamer-Douglas-Peucker (RDP)\n\n```ruby\nKhiva::Dimensionality.ramer_douglas_peucker(a, epsilon)\n```\n\nSymbolic Aggregate ApproXimation (SAX)\n\n```ruby\nKhiva::Dimensionality.sax(a, alphabet_size)\n```\n\nVisvalingam\n\n```ruby\nKhiva::Dimensionality.visvalingam(a, num_points)\n```\n\n## Distances\n\nDynamic time warping (DTW) distance\n\n```ruby\nKhiva::Distances.dtw(tss)\n```\n\nEuclidean distance\n\n```ruby\nKhiva::Distances.euclidean(tss)\n```\n\nHamming distance\n\n```ruby\nKhiva::Distances.hamming(tss)\n```\n\nManhattan distance\n\n```ruby\nKhiva::Distances.manhattan(tss)\n```\n\nShape-based distance (SBD)\n\n```ruby\nKhiva::Distances.sbd(tss)\n```\n\nSquared Euclidean distance\n\n```ruby\nKhiva::Distances.squared_euclidean(tss)\n```\n\n## Features\n\nSum of square values\n\n```ruby\nKhiva::Features.abs_energy(tss)\n```\n\nAbsolute sum of changes\n\n```ruby\nKhiva::Features.absolute_sum_of_changes(tss)\n```\n\nAggregated autocorrelation\n\n```ruby\nKhiva::Features.aggregated_autocorrelation(tss, aggregation_function)\n```\n\nApproximate entropy\n\n```ruby\nKhiva::Features.approximate_entropy(tss, m, r)\n```\n\nAutocorrelation\n\n```ruby\nKhiva::Features.auto_correlation(tss, max_lag, unbiased)\n```\n\nAuto-covariance\n\n```ruby\nKhiva::Features.auto_covariance(tss, unbiased: false)\n```\n\nBinned entropy\n\n```ruby\nKhiva::Features.binned_entropy(tss, max_bins)\n```\n\nSchreiber, T. and Schmitz, A. (1997) measure of non-linearity\n\n```ruby\nKhiva::Features.c3(tss, lag)\n```\n\nEstimate of complexity defined by Batista, Gustavo EAPA, et al (2014)\n\n```ruby\nKhiva::Features.cid_ce(tss, z_normalize)\n```\n\nNumber of values above the mean\n\n```ruby\nKhiva::Features.count_above_mean(tss)\n```\n\nNumber of values below the mean\n\n```ruby\nKhiva::Features.count_below_mean(tss)\n```\n\nCross-correlation\n\n```ruby\nKhiva::Features.cross_correlation(xss, yss, unbiased)\n```\n\nCross-covariance\n\n```ruby\nKhiva::Features.cross_covariance(xss, yss, unbiased)\n```\n\nEnergy ratio by chunks\n\n```ruby\nKhiva::Features.energy_ratio_by_chunks(arr, num_segments, segment_focus)\n```\n\nThe spectral centroid (mean), variance, skew, and kurtosis of the absolute fourier transform spectrum\n\n```ruby\nKhiva::Features.fft_aggregated(tss)\n```\n\nFirst location of the maximum value\n\n```ruby\nKhiva::Features.first_location_of_maximum(tss)\n```\n\nFirst location of the minimum value\n\n```ruby\nKhiva::Features.first_location_of_minimum(tss)\n```\n\nMaximum is duplicated\n\n```ruby\nKhiva::Features.has_duplicate_max(tss)\n```\n\nMinimum is duplicated\n\n```ruby\nKhiva::Features.has_duplicate_min(tss)\n```\n\nAny elements are duplicated\n\n```ruby\nKhiva::Features.has_duplicates(tss)\n```\n\nIndex of the mass quantile\n\n```ruby\nKhiva::Features.index_mass_quantile(tss, q)\n```\n\nKurtosis\n\n```ruby\nKhiva::Features.kurtosis(tss)\n```\n\nStandard deviation above threshold\n\n```ruby\nKhiva::Features.large_standard_deviation(tss, r)\n```\n\nLast location of the maximum value\n\n```ruby\nKhiva::Features.last_location_of_maximum(tss)\n```\n\nLast location of the minimum value\n\n```ruby\nKhiva::Features.last_location_of_minimum(tss)\n```\n\nLength of the series\n\n```ruby\nKhiva::Features.length(tss)\n```\n\nLocal maximals\n\n```ruby\nKhiva::Features.local_maximals(tss)\n```\n\nLength of the longest consecutive subsequence above the mean\n\n```ruby\nKhiva::Features.longest_strike_above_mean(tss)\n```\n\nLength of the longest consecutive subsequence below the mean\n\n```ruby\nKhiva::Features.longest_strike_below_mean(tss)\n```\n\nMaximum\n\n```ruby\nKhiva::Features.maximum(tss)\n```\n\nMean\n\n```ruby\nKhiva::Features.mean(tss)\n```\n\nMean absolute change\n\n```ruby\nKhiva::Features.mean_absolute_change(tss)\n```\n\nMean change\n\n```ruby\nKhiva::Features.mean_change(tss)\n```\n\nMean of a central approximation of the second derivative\n\n```ruby\nKhiva::Features.mean_second_derivative_central(tss)\n```\n\nMedian\n\n```ruby\nKhiva::Features.median(tss)\n```\n\nMinimum\n\n```ruby\nKhiva::Features.minimum(tss)\n```\n\nNumber of m-crossings\n\n```ruby\nKhiva::Features.number_crossing_m(tss, m)\n```\n\nNumber of peaks of at least support `n`\n\n```ruby\nKhiva::Features.number_peaks(tss, n)\n```\n\nPartial autocorrelation\n\n```ruby\nKhiva::Features.partial_autocorrelation(tss, lags)\n```\n\nPercentage of unique values present more than once\n\n```ruby\nKhiva::Features.percentage_of_reoccurring_datapoints_to_all_datapoints(tss, sorted)\n```\n\nPercentage of values present more than once\n\n```ruby\nKhiva::Features.percentage_of_reoccurring_values_to_all_values(tss, sorted)\n```\n\nQuantile\n\n```ruby\nKhiva::Features.quantile(tss, q, precision: 100000000)\n```\n\nCount of values within the interval [min, max]\n\n```ruby\nKhiva::Features.range_count(tss, min, max)\n```\n\nRatio of values more than `r` sigma away from the mean\n\n```ruby\nKhiva::Features.ratio_beyond_r_sigma(tss, coeff)\n```\n\nRatio of unique values\n\n```ruby\nKhiva::Features.ratio_value_number_to_time_series_length(tss)\n```\n\nSample entropy\n\n```ruby\nKhiva::Features.sample_entropy(tss)\n```\n\nSkewness\n\n```ruby\nKhiva::Features.skewness(tss)\n```\n\nCross power spectral density at different frequencies\n\n```ruby\nKhiva::Features.spkt_welch_density(tss, coeff)\n```\n\nStandard deviation\n\n```ruby\nKhiva::Features.standard_deviation(tss)\n```\n\nSum of all data points present more than once\n\n```ruby\nKhiva::Features.sum_of_reoccurring_datapoints(tss, sorted: false)\n```\n\nSum of all values present more than once\n\n```ruby\nKhiva::Features.sum_of_reoccurring_values(tss, sorted: false)\n```\n\nSum of values\n\n```ruby\nKhiva::Features.sum_values(tss)\n```\n\nIf looks symmetric\n\n```ruby\nKhiva::Features.symmetry_looking(tss, r)\n```\n\nTime reversal asymmetry\n\n```ruby\nKhiva::Features.time_reversal_asymmetry_statistic(tss, lag)\n```\n\nNumber of occurrences of a value\n\n```ruby\nKhiva::Features.value_count(tss, v)\n```\n\nVariance\n\n```ruby\nKhiva::Features.variance(tss)\n```\n\nIf variance is larger than one\n\n```ruby\nKhiva::Features.variance_larger_than_standard_deviation(tss)\n```\n\n## Library\n\nGet backend info\n\n```ruby\nKhiva::Library.backend_info\n```\n\nGet current backend\n\n```ruby\nKhiva::Library.backend\n```\n\nGet available backends\n\n```ruby\nKhiva::Library.backends\n```\n\nSet backend - `:default`, `:cpu`, `:cuda`, `:opencl`\n\n```ruby\nKhiva::Library.set_backend(:cpu)\n```\n\nSet device\n\n```ruby\nKhiva::Library.set_device(device_id)\n```\n\nGet device id\n\n```ruby\nKhiva::Library.device_id\n```\n\nGet device count\n\n```ruby\nKhiva::Library.device_count\n```\n\nSet device memory in GB\n\n```ruby\nKhiva::Library.set_device_memory_in_gb(1.5)\n```\n\nGet version\n\n```ruby\nKhiva::Library.version\n```\n\n## Linalg\n\n```ruby\nKhiva::Linalg.lls(a, b)\n```\n\n## Matrix\n\nFind discords\n\n```ruby\ndistances, indices, subsequences = Khiva::Matrix.find_best_n_discords(profile, index, m, n)\n```\n\nFind motifs\n\n```ruby\ndistances, indices, subsequences = Khiva::Matrix.find_best_n_motifs(profile, index, m, n)\n```\n\nFind best occurences\n\n```ruby\ndistances, indices = Khiva::Matrix.find_best_n_occurrences(q, t, n)\n```\n\nMueen’s Algorithm for Similarity Search (MASS)\n\n```ruby\ndistances = Khiva::Matrix.mass(q, t)\n```\n\nCalculate the matrix profile between `ta` and `tb` using a subsequence length of `m` with the STOMP algorithm\n\n```ruby\nprofile, index = Khiva::Matrix.stomp(ta, tb, m)\n```\n\nCalculate the matrix profile between `t` and itself using a subsequence length of `m` with the STOMP algorithm\n\n```ruby\nprofile, index = Khiva::Matrix.stomp_self_join(t, m)\n```\n\nCalculate the matrix profile between `ta` and `tb` using a subsequence length of `m`\n\n```ruby\nprofile, index = Khiva::Matrix.matrix_profile(ta, tb, m)\n```\n\nCalculate the matrix profile between `t` and itself using a subsequence length of `m`\n\n```ruby\nprofile, index = Khiva::Matrix.matrix_profile_self_join(t, m)\n```\n\nGet chains\n\n```ruby\nKhiva::Matrix.chains(tss, m)\n```\n\n## Normalization\n\nDecimal scaling\n\n```ruby\nKhiva::Normalization.decimal_scaling_norm(tss)\nKhiva::Normalization.decimal_scaling_norm!(tss)\n```\n\nMax min\n\n```ruby\nKhiva::Normalization.max_min_norm(tss)\nKhiva::Normalization.max_min_norm!(tss)\n```\n\nMean\n\n```ruby\nKhiva::Normalization.mean_norm(tss)\nKhiva::Normalization.mean_norm!(tss)\n```\n\nZnorm\n\n```ruby\nKhiva::Normalization.znorm(tss)\nKhiva::Normalization.znorm!(tss)\n```\n\n## Polynomial\n\nLeast squares polynomial fit\n\n```ruby\nKhiva::Polynomial.polyfit(x, y, deg)\n```\n\n## Regression\n\nLinear least squares regression\n\n```ruby\nslope, intercept, rvalue, pvalue, stderrest = Khiva::Regression.linear(xss, yss)\n```\n\n## Regularization\n\n```ruby\nKhiva::Regularization.group_by(tss, aggregation_function, columns_key: 1, n_columns_value: 1)\n```\n\n## Statistics\n\nCovariance\n\n```ruby\nKhiva::Statistics.covariance(tss, unbiased: false)\n```\n\nKurtosis\n\n```ruby\nKhiva::Statistics.kurtosis(tss)\n```\n\nLjung-Box\n\n```ruby\nKhiva::Statistics.ljung_box(tss, lags)\n```\n\nMoment\n\n```ruby\nKhiva::Statistics.moment(tss, k)\n```\n\nQuantile\n\n```ruby\nKhiva::Statistics.quantile(tss, q, precision: 1e-8)\n```\n\nQuantiles cut\n\n```ruby\nKhiva::Statistics.quantiles_cut(tss, quantiles, precision: 1e-8)\n```\n\nStandard deviation\n\n```ruby\nKhiva::Statistics.sample_stdev(tss)\n```\n\nSkewness\n\n```ruby\nKhiva::Statistics.skewness(tss)\n```\n\n## Khiva Installation\n\n### Linux - Ubuntu\n\nInstall ArrayFire:\n\n```sh\nsudo apt-key adv --fetch-key https://repo.arrayfire.com/GPG-PUB-KEY-ARRAYFIRE-2020.PUB\necho \"deb [arch=amd64] https://repo.arrayfire.com/debian all main\" | sudo tee /etc/apt/sources.list.d/arrayfire.list\nsudo apt-get update\nsudo apt-get install arrayfire-unified3 arrayfire-cpu3-openblas arrayfire-opencl3-openblas\n```\n\nAnd install Khiva:\n\n```sh\nwget https://github.com/shapelets/khiva/releases/download/v0.5.0/khiva-khiva_0.5.0_amd64.deb\nsudo dpkg -i khiva-khiva_0.5.0_amd64.deb\nsudo ldconfig\n```\n\n### Linux - Other\n\nSee [instructions](https://khiva.readthedocs.io/en/latest/gettingStarted.html).\n\n### Mac\n\nRun:\n\n```sh\nbrew install khiva\n```\n\n### Windows\n\nSee [instructions](https://khiva.readthedocs.io/en/latest/gettingStarted.html).\n\n## Credits\n\nThis library is modeled after the [Khiva-Python API](https://github.com/shapelets/khiva-python).\n\n## History\n\nView the [changelog](https://github.com/ankane/khiva-ruby/blob/master/CHANGELOG.md)\n\n## Contributing\n\nEveryone is encouraged to help improve this project. Here are a few ways you can help:\n\n- [Report bugs](https://github.com/ankane/khiva-ruby/issues)\n- Fix bugs and [submit pull requests](https://github.com/ankane/khiva-ruby/pulls)\n- Write, clarify, or fix documentation\n- Suggest or add new features\n\nTo get started with development:\n\n```sh\ngit clone https://github.com/ankane/khiva-ruby.git\ncd khiva-ruby\nbundle install\nbundle exec rake test\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fankane%2Fkhiva-ruby","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fankane%2Fkhiva-ruby","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fankane%2Fkhiva-ruby/lists"}