{"id":14977771,"url":"https://github.com/visco01/gtfs_stops_clustering","last_synced_at":"2025-06-22T09:40:14.304Z","repository":{"id":211168994,"uuid":"728379619","full_name":"Visco01/gtfs_stops_clustering","owner":"Visco01","description":"A gem to read GTFS stops data and create clusters based on coordinates and stop names' similarities.","archived":false,"fork":false,"pushed_at":"2024-05-23T10:18:32.000Z","size":55,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-20T19:19:11.404Z","etag":null,"topics":["dbscan","dbscan-clustering","gtfs","redis","ruby-gem"],"latest_commit_sha":null,"homepage":"https://rubygems.org/gems/gtfs_stops_clustering","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Visco01.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","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":"2023-12-06T20:19:28.000Z","updated_at":"2024-05-23T10:18:33.000Z","dependencies_parsed_at":"2024-09-14T23:06:00.465Z","dependency_job_id":null,"html_url":"https://github.com/Visco01/gtfs_stops_clustering","commit_stats":null,"previous_names":["visco01/gtfs_stops_clustering"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/Visco01/gtfs_stops_clustering","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Visco01%2Fgtfs_stops_clustering","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Visco01%2Fgtfs_stops_clustering/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Visco01%2Fgtfs_stops_clustering/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Visco01%2Fgtfs_stops_clustering/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Visco01","download_url":"https://codeload.github.com/Visco01/gtfs_stops_clustering/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Visco01%2Fgtfs_stops_clustering/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261272605,"owners_count":23133795,"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","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":["dbscan","dbscan-clustering","gtfs","redis","ruby-gem"],"created_at":"2024-09-24T13:56:18.537Z","updated_at":"2025-06-22T09:40:09.242Z","avatar_url":"https://github.com/Visco01.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GTFS Stops clustering \n[![Gem Version](https://badge.fury.io/rb/gtfs_stops_clustering.svg)](https://badge.fury.io/rb/gtfs_stops_clustering)\n\nGTFS Stops Clustering is a Ruby Gem designed to read [GTFS](https://gtfs.org) (General Transit Feed Specification) stops data and create clusters based on the following parameters:\n\n- `GTFS paths` [Required]: array of gtfs zip files paths whose stops will be combined in the clustering algorithm\n- `Epsilon` [Required]: the maximum distance (in km) between 2 stops for them to be considered neighbors of one another (e.g.: 0.01, 0.5, 2 etc.)\n- `Min Points` [Required]: the minimum number of neighbors a point needs to have to be considered a core point (e.g.: 3, 5, 10 etc.)\n- `Names Similarity` [Optional]: Besides geographical proximity, the algorithm also considers the similarity between stop names using techniques like string similarity measures. This enhances the clustering by including stops with similar names within the same cluster (e.g.: all values between 0 and 1. The more the value is in proximity of 1, the more similar the stop names need to be considered points of the same cluster). The default value is 1, so if you want to create clusters based only on stop positions, leave this to 0.\n- `Stop config file` (CSV file path) [Optional]: This file is specifically designed to handle certain cases where stop names need to be altered or mapped to different names before running the clustering algorithm. Each entry consists of two columns:\n**stop_name**: This column contains the original name of the stop that requires modification or mapping to another name. **cluster_name**: This column specifies the name to which the original stop name should be changed or mapped during the clustering process.\n\nIt utilizes the [DBSCAN](https://en.wikipedia.org/wiki/DBSCAN) Density-Based algorithm to perform clustering. I based my core algorithm on the gem [Dbscan](https://github.com/matiasinsaurralde/dbscan)\n\n### Stops config file example\n\nHere is an example of a stops_config CSV file:\n\n```csv\nstop_name,cluster_name\nStop Name To Be Changed,Actual Name\nAmargosa Valley (Demo),Amargosa Valley\nE Main St / S Irving St (Demo),E Main St / S Irving St\n```\n\nIn this case, passing this CSV file to the clustering algorithm, **Amargosa Valley (Demo)** will be renamed **Amargarosa Valley**, and so on for all the entries provided. The reason why I needed to implement this feature is simply because I was dealing with bad stops names (typo) provided by default within the GTFS I was working on. [v0.1.7] After performing the algorithm, the original gtfs stops names will be restored.\n\n## Requirements\n\nIt is essential to have a **Redis server instance running locally (on default port 6379)** because the algorithm leverages Redis geospatial queries for efficient spatial operations.\nThe Redis server is utilized to optimize geospatial queries, allowing the clustering algorithm to efficiently process proximity-related computations required during the clustering process.\nPlease ensure that a Redis server is installed and running on your local machine to utilize the gem effectively.\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'gtfs_stops_clustering', '~\u003e 0.1.7'\n```\nAnd run the following command\n\n```bash\n$ bundle install\n```\n\nIf bundler is not being used to manage dependencies, install the gem by executing:\n\n```bash\n$ gem install gtfs_stops_clustering\n```\n\n## Usage\n\n```ruby\nrequire 'gtfs_stops_clustering'\ninclude GtfsStopsClustering\n\ngtfs_paths = [\"path/to/gtfs/zip\"]\n\nclusters = build_clusters(gtfs_paths, 0.3, 1, 0.85)\n\nclusters.each do |index, cluster|\n  puts index\n  cluster.each do |stop|\n    puts stop.inspect\n  end\nend\n```\n\nIn this case, I'm showing the output referred to the GTFS file located in `test/fixtures/sample-feed-2.zip` (which is the sample-feed provided by Google, but changed a bit in order to create \"clusterable\" stops since they all were too far to be clustered). In this case I omitted the optional parameter `stops config`\n\n```\n-1\n{:stop_id=\u003e\"4\", :stop_code=\u003enil, :cluster_name=\u003enil, :cluster_pos=\u003e[], :stop_name=\u003e\"Stagecoach Hotel \u0026 Casino (Demo)\", :stop_lat=\u003e\"36.915682\", :stop_lon=\u003e\"-116.751677\", :parent_station=\u003enil}\n{:stop_id=\u003e\"6\", :stop_code=\u003enil, :cluster_name=\u003enil, :cluster_pos=\u003e[], :stop_name=\u003e\"Alone stop (sad)\", :stop_lat=\u003e\"36.914944\", :stop_lon=\u003e\"-116.761472\", :parent_station=\u003enil}\n{:stop_id=\u003e\"8\", :stop_code=\u003enil, :cluster_name=\u003enil, :cluster_pos=\u003e[], :stop_name=\u003e\"E Main St / S Irving St (Demo)\", :stop_lat=\u003e\"36.905697\", :stop_lon=\u003e\"-116.76218\", :parent_station=\u003enil}\n{:stop_id=\u003e\"9\", :stop_code=\u003enil, :cluster_name=\u003enil, :cluster_pos=\u003e[], :stop_name=\u003e\"Amargosa Valley (Demo)\", :stop_lat=\u003e\"36.641496\", :stop_lon=\u003e\"-116.40094\", :parent_station=\u003enil}\n0\n{:stop_id=\u003e\"1\", :stop_code=\u003enil, :cluster_name=\u003e\"Awesome Stop Name\", :cluster_pos=\u003e[36.425286, -117.133156], :stop_name=\u003e\"Awesome stop name 1\", :stop_lat=\u003e\"36.425288\", :stop_lon=\u003e\"-117.133162\", :parent_station=\u003enil}\n{:stop_id=\u003e\"5\", :stop_code=\u003enil, :cluster_name=\u003e\"Awesome Stop Name\", :cluster_pos=\u003e[36.425286, -117.133156], :stop_name=\u003e\"Awesome stop name 2\", :stop_lat=\u003e\"36.425284\", :stop_lon=\u003e\"-117.133150\", :parent_station=\u003enil}\n1\n{:stop_id=\u003e\"2\", :stop_code=\u003enil, :cluster_name=\u003e\"Nye County Airport\", :cluster_pos=\u003e[36.868429, -116.78467699999999], :stop_name=\u003e\"Nye County Airport A1\", :stop_lat=\u003e\"36.868446\", :stop_lon=\u003e\"-116.784582\", :parent_station=\u003enil}\n{:stop_id=\u003e\"3\", :stop_code=\u003enil, :cluster_name=\u003e\"Nye County Airport\", :cluster_pos=\u003e[36.868429, -116.78467699999999], :stop_name=\u003e\"Nye County Airport A2\", :stop_lat=\u003e\"36.868417\", :stop_lon=\u003e\"-116.784352\", :parent_station=\u003enil}\n{:stop_id=\u003e\"7\", :stop_code=\u003enil, :cluster_name=\u003e\"Nye County Airport\", :cluster_pos=\u003e[36.868429, -116.78467699999999], :stop_name=\u003e\"Nye County Airport A5\", :stop_lat=\u003e\"36.868424\", :stop_lon=\u003e\"-116.785097\", :parent_station=\u003enil}\n```\n\n## Development\n\nAfter checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.\n\nTo install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/gtfs_stops_clustering. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/gtfs_stops_clustering/blob/main/CODE_OF_CONDUCT.md).\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n\n## Code of Conduct\n\nEveryone interacting in the GtfsStopsClustering project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/gtfs_stops_clustering/blob/main/CODE_OF_CONDUCT.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvisco01%2Fgtfs_stops_clustering","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvisco01%2Fgtfs_stops_clustering","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvisco01%2Fgtfs_stops_clustering/lists"}