gtfs_stops_clustering 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 32c396f8f9377660da84a4b29d78657e23efcfefe01e6d05368894dd1ffbf07d
4
- data.tar.gz: 42f3961fb4a896fb3f25c3f113672a0ac8894d74458270bfce2fef82f5e50e11
3
+ metadata.gz: d10d21f2d65afcf335560f35f8a34e4c8e46b3e6eeb6b7c74d9edf73e3336227
4
+ data.tar.gz: 67f4f260b43a6ac2f8af21b8c1a5471ee241b3c86f6a8532c55e0554268cdaa0
5
5
  SHA512:
6
- metadata.gz: 197ec5fb775f93c61c1207392bb2b0a136c09b61572327d2855b9f0c73bf1dc94f552b6665d842a757c20e06248692001ff013c23407e3bc94ed7a024ca5dbd0
7
- data.tar.gz: 88c0c3d4106abf305d0ac7a4196a6612f40745bf2632ffadab32673d3fb60f04800a2d4de44027fa9fb4a3c8c03db206881dccc91505fb15e48253e56e85952c
6
+ metadata.gz: e5ef45bb1402420422984e19918edfe60c5cc73fac8d503be3f605bd83c4b97460a688e79bba16e901cb42ecf358571cc1380467920e2c9b051be08b0fcff5fb
7
+ data.tar.gz: '0349797d0744abe6432ab20f262ac766118b2a3153b1e5dbb2796d2c3eb359fccc109bdadc17affbe43b9824457701daa5d3a1c434fe43ab40c3c1534dbce382'
@@ -1,12 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # lib/data_import.rb
2
4
 
3
- require 'csv'
4
- require 'gtfs'
5
+ require "csv"
6
+ require "gtfs"
5
7
 
8
+ # DataImport module
6
9
  module DataImport
7
- VERSION='0.0.1'
8
10
  attr_accessor :data_import
9
11
 
12
+ # DataImport class
10
13
  class DataImport
11
14
  attr_accessor :stops, :stops_config_file, :stops_names, :stops_corner_cases, :stops_data, :stops_redis_geodata
12
15
 
@@ -22,13 +25,13 @@ module DataImport
22
25
  end
23
26
 
24
27
  def import_stops_corner_cases
25
- if File.exist?(@stops_config_file)
26
- CSV.foreach(@stops_config_file, headers: true) do |row|
27
- stop_name = row['stop_name']
28
- cluster_name = row['cluster_name']
28
+ return unless File.exist?(@stops_config_file)
29
+
30
+ CSV.foreach(@stops_config_file, headers: true) do |row|
31
+ stop_name = row["stop_name"]
32
+ cluster_name = row["cluster_name"]
29
33
 
30
- stops_corner_cases << { stop_name: stop_name, cluster_name: cluster_name }
31
- end
34
+ stops_corner_cases << { stop_name: stop_name, cluster_name: cluster_name }
32
35
  end
33
36
  end
34
37
 
@@ -38,13 +41,20 @@ module DataImport
38
41
  longitude = row.lon
39
42
  stop_name = row.name
40
43
 
41
- stop_name = @stops_corner_cases.find { |entry| entry[:stop_name] == stop_name }[:cluster_name] if stops_corner_cases.find { |entry| entry[:stop_name] == stop_name }
44
+ stop_name = stop_name_from_corner_cases(stop_name)
42
45
 
43
46
  @stops_names << stop_name
44
47
  @stops_data << [latitude, longitude]
45
48
  @stops_redis_geodata << [longitude, latitude, "#{longitude},#{latitude}"]
46
49
  end
47
50
  end
51
+
52
+ def stop_name_from_corner_cases(stop_name)
53
+ csv_entry = @stops_corner_cases.find do |entry|
54
+ entry[:stop_name] == stop_name
55
+ end
56
+ csv_entry.nil? ? stop_name : csv_entry[:cluster_name]
57
+ end
48
58
  end
49
59
 
50
60
  def import_stops_data(*args)
@@ -56,5 +66,3 @@ module DataImport
56
66
  }
57
67
  end
58
68
  end
59
-
60
- include DataImport
@@ -1,33 +1,47 @@
1
- ## https://github.com/shiguodong/dbscan (fork)
1
+ # frozen_string_literal: true
2
2
 
3
- require 'distance_measures'
4
- require 'text'
5
- require 'geocoder'
6
- require_relative 'redis_geodata'
3
+ # lib/gtfs_stops_clustering/dbscan.rb
7
4
 
5
+ require "distance_measures"
6
+ require "text"
7
+ require "geocoder"
8
+ require_relative "redis_geodata"
9
+
10
+ # Array class
8
11
  class Array
9
- def haversine_distance2(n)
10
- Geocoder::Calculations.distance_between(self, n)
12
+ def haversine_distance2(other)
13
+ Geocoder::Calculations.distance_between(self, other)
11
14
  end
12
15
  end
13
16
 
17
+ # DBSCAN module
14
18
  module DBSCAN
19
+ # Clusterer class
15
20
  class Clusterer
21
+ include RedisGeodata
16
22
  attr_accessor :points, :options, :clusters
17
23
 
18
24
  def initialize(points, stops_redis_geodata, options = {})
19
25
  options[:distance] = :euclidean_distance unless options[:distance]
20
26
  options[:labels] = [] unless options[:labels]
21
27
 
22
- c = 0
23
28
  redis_geodata_import(stops_redis_geodata, options[:epsilon])
24
- @points = points.map { |e| po = Point.new(e, options[:labels][c]); c +=1; po }
25
29
  @options = options
26
- @clusters = {-1 => []}
30
+ init_points(points)
31
+ @clusters = { -1 => [] }
27
32
 
28
33
  clusterize!
29
34
  end
30
35
 
36
+ def init_points(points)
37
+ c = 0
38
+ @points = points.map do |e|
39
+ po = Point.new(e, @options[:labels][c])
40
+ c += 1
41
+ po
42
+ end
43
+ end
44
+
31
45
  def clusterize!
32
46
  current_cluster = -1
33
47
  @points.each do |point|
@@ -49,10 +63,10 @@ module DBSCAN
49
63
  # Get Cluster Position
50
64
  cluster_pos = find_cluster_position(clusters[current_cluster])
51
65
 
52
- clusters[current_cluster].each { |e|
66
+ clusters[current_cluster].each do |e|
53
67
  e.cluster_name = cluster_name
54
68
  e.cluster_pos = cluster_pos
55
- }
69
+ end
56
70
  else
57
71
  clusters[-1].push(point)
58
72
  end
@@ -91,9 +105,11 @@ module DBSCAN
91
105
  neighbors = []
92
106
  geosearch_results = geosearch(point.items[1], point.items[0])
93
107
  geosearch_results.each do |neighbor_pos|
94
- coordinates = neighbor_pos.split(',')
95
- neighbor = @points.find { |point| point.items[0] == coordinates[1] &&
96
- point.items[1] == coordinates[0] }
108
+ coordinates = neighbor_pos.split(",")
109
+ neighbor = @points.find do |elem|
110
+ elem.items[0] == coordinates[1] &&
111
+ elem.items[1] == coordinates[0]
112
+ end
97
113
  next unless neighbor
98
114
 
99
115
  string_distance = Text::Levenshtein.distance(point.label.downcase, neighbor.label.downcase)
@@ -112,9 +128,7 @@ module DBSCAN
112
128
 
113
129
  if new_points.size >= options[:min_points]
114
130
  new_points.each do |p|
115
- unless neighbors.include?(p)
116
- neighbors.push(p)
117
- end
131
+ neighbors.push(p) unless neighbors.include?(p)
118
132
  end
119
133
  end
120
134
  end
@@ -127,32 +141,31 @@ module DBSCAN
127
141
 
128
142
  cluster_points
129
143
  end
130
- end
131
144
 
132
- def find_cluster_name(labels)
133
- words = labels.map { |label| label.strip.split }
134
- common_title = ''
145
+ def find_cluster_name(labels)
146
+ words = labels.map { |label| label.strip.split }
147
+ common_title = ""
135
148
 
136
- # Loop through each word index starting from the first
137
- (0...words.first.length).each do |i|
138
- words_at_index = words.map { |word_list| word_list[i] }
149
+ # Loop through each word index starting from the first
150
+ (0...words.first.length).each do |i|
151
+ words_at_index = words.map { |word_list| word_list[i] }
139
152
 
140
- break unless words_at_index.uniq.length == 1
153
+ break unless words_at_index.uniq.length == 1
141
154
 
142
- common_title += " #{words_at_index.first.capitalize}"
143
- end
144
-
145
- common_title.strip! ? common_title : labels.first
146
- end
155
+ common_title += " #{words_at_index.first.capitalize}"
156
+ end
147
157
 
148
- def find_cluster_position(cluster)
149
- total_lat = cluster.map { |e| e.items[0].to_f }.sum
150
- total_lon = cluster.map { |e| e.items[1].to_f }.sum
151
- avg_lat = total_lat / cluster.size
152
- avg_lon = total_lon / cluster.size
153
- [avg_lat, avg_lon]
158
+ common_title.strip ? common_title : labels.first
159
+ end
160
+ def find_cluster_position(cluster)
161
+ total_lat = cluster.map { |e| e.items[0].to_f }.sum
162
+ total_lon = cluster.map { |e| e.items[1].to_f }.sum
163
+ avg_lat = total_lat / cluster.size
164
+ avg_lon = total_lon / cluster.size
165
+ [avg_lat, avg_lon]
166
+ end
154
167
  end
155
-
168
+ # Point class
156
169
  class Point
157
170
  attr_accessor :items, :cluster, :visited, :label, :cluster_name, :cluster_pos
158
171
 
@@ -176,5 +189,3 @@ module DBSCAN
176
189
  clusterer.labeled_results
177
190
  end
178
191
  end
179
-
180
- include DBSCAN
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ # lib/input_consistency_checks.rb
4
+
5
+ # InputConsistencyChecks module
6
+ module InputConsistencyChecks
7
+ # InputConsistencyChecks class
8
+ class InputConsistencyChecks
9
+ attr_accessor :gtfs_paths, :epsilon, :min_points, :names_similarity, :stops_config_path
10
+
11
+ def initialize(gtfs_paths, epsilon, min_points, names_similarity, stops_config_path)
12
+ @gtfs_paths = gtfs_paths
13
+ @stops_config_path = stops_config_path
14
+ @epsilon = epsilon
15
+ @min_points = min_points
16
+ @names_similarity = names_similarity
17
+ input_consistency_checks
18
+ end
19
+
20
+ def input_consistency_checks
21
+ gtfs_paths_check
22
+ epsilon_check
23
+ min_points_check
24
+ names_similarity_check
25
+ end
26
+
27
+ def gtfs_paths_check
28
+ raise ArgumentError, "gtfs_paths cannot be nil" if @gtfs_paths.nil?
29
+ raise ArgumentError, "gtfs_paths must be an Array" unless @gtfs_paths.is_a?(Array)
30
+ raise ArgumentError, "gtfs_paths must not be empty" if @gtfs_paths.empty?
31
+ end
32
+
33
+ def epsilon_check
34
+ raise ArgumentError, "epsilon must be a Float" unless @epsilon.is_a?(Float)
35
+ raise ArgumentError, "epsilon must be greater than 0" if @epsilon.negative?
36
+ end
37
+
38
+ def min_points_check
39
+ raise ArgumentError, "min_points must be an Integer" unless @min_points.is_a?(Integer)
40
+ raise ArgumentError, "min_points must be greater than 0" if @min_points.negative?
41
+ end
42
+
43
+ def names_similarity_check
44
+ raise ArgumentError, "names_similarity must be a Float" unless @names_similarity.is_a?(Float)
45
+ raise ArgumentError, "names_similarity must be between 0 and 1" if @names_similarity.negative? || @names_similarity > 1
46
+ end
47
+ end
48
+
49
+ def input_consistency_checks(gtfs_paths, epsilon, min_points, names_similarity, stop_config_path)
50
+ @input_consistency_checks = InputConsistencyChecks.new(gtfs_paths, epsilon, min_points, names_similarity, stop_config_path)
51
+ end
52
+ end
@@ -1,17 +1,21 @@
1
- # lib/redis_geodata.rb
2
- require 'redis'
1
+ # frozen_string_literal: true
3
2
 
3
+ # lib/gtfs_stops_clustering/redis_geodata.rb
4
+
5
+ require "redis"
6
+
7
+ # RedisGeodata module
4
8
  module RedisGeodata
5
- VERSION='0.0.1'
6
9
  attr_accessor :redis
7
10
 
11
+ # RedisGeodata class
8
12
  class RedisGeodata
9
13
  attr_accessor :stops, :key, :redis, :epsilon
10
14
 
11
15
  def initialize(stops, epsilon)
12
- @redis = Redis.new(url: 'redis://127.0.0.1:6379')
16
+ @redis = Redis.new(url: "redis://127.0.0.1:6379")
13
17
  @stops = stops
14
- @key = 'stops'
18
+ @key = "stops"
15
19
  @epsilon = epsilon
16
20
  geoadd
17
21
  end
@@ -22,8 +26,8 @@ module RedisGeodata
22
26
  end
23
27
 
24
28
  def geosearch(longitude, latitude)
25
- list = @redis.georadius(@key, longitude, latitude, @epsilon, 'km')
26
- list.reject! { |point| point == longitude.to_s + "," + latitude.to_s }
29
+ list = @redis.georadius(@key, longitude, latitude, @epsilon, "km")
30
+ list.reject! { |point| point == "#{longitude},#{latitude}" }
27
31
  list
28
32
  end
29
33
  end
@@ -36,5 +40,3 @@ module RedisGeodata
36
40
  @redis.geosearch(*args)
37
41
  end
38
42
  end
39
-
40
- include RedisGeodata
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GtfsStopsClustering
4
- VERSION = "0.1.2"
4
+ VERSION = "0.1.3"
5
5
  end
@@ -1,31 +1,37 @@
1
- #!/usr/bin/env ruby
1
+ # frozen_string_literal: true
2
+
2
3
  # lib/gtfs_stops_clustering.rb
3
- require 'rubygems'
4
- require 'bundler/setup'
4
+
5
+ require "rubygems"
6
+ require "bundler/setup"
5
7
  require_relative "gtfs_stops_clustering/version"
6
- require 'gtfs'
7
- require 'csv'
8
- require_relative './gtfs_stops_clustering/data_import'
9
- require_relative './gtfs_stops_clustering/dbscan'
8
+ require "gtfs"
9
+ require "csv"
10
+ require_relative "./gtfs_stops_clustering/data_import"
11
+ require_relative "./gtfs_stops_clustering/dbscan"
12
+ require_relative "./gtfs_stops_clustering/input_consistency_checks"
10
13
 
14
+ # GtfsStopClustering module
11
15
  module GtfsStopsClustering
12
- VERSION = GtfsStopsClustering::VERSION
13
16
  attr_accessor :gtfs_stops_clustering
14
17
 
18
+ # GtfsStopsClustering class
15
19
  class GtfsStopsClustering
16
- attr_accessor :clusters, :gtfs_urls, :gtfs_stops, :stops_config_path, :epsilon, :min_points, :names_similarity
20
+ include InputConsistencyChecks
21
+ include DataImport
22
+ include DBSCAN
23
+ attr_accessor :clusters, :gtfs_paths, :gtfs_stops, :stops_config_path, :epsilon, :min_points, :names_similarity
17
24
 
18
- def initialize(gtfs_urls, epsilon, min_points, names_similarity, stops_config_path)
25
+ def initialize(gtfs_paths, epsilon, min_points, names_similarity, stops_config_path)
26
+ @gtfs_paths = gtfs_paths
27
+ @stops_config_path = stops_config_path
28
+ @epsilon = epsilon
29
+ @min_points = min_points
30
+ @names_similarity = names_similarity
31
+ input_consistency_checks(@gtfs_paths, @epsilon, @min_points, @names_similarity, @stops_config_path)
19
32
  @clusters = []
20
- unless gtfs_urls.empty?
21
- @gtfs_paths = gtfs_urls
22
- @stops_config_path = stops_config_path
23
- @epsilon = epsilon
24
- @min_points = min_points
25
- @names_similarity = names_similarity
26
- @gtfs_stops = create_stops_merged
27
- clusterize_stops_csv(@gtfs_stops)
28
- end
33
+ @gtfs_stops = create_stops_merged
34
+ clusterize_stops
29
35
  end
30
36
 
31
37
  def create_stops_merged
@@ -37,11 +43,20 @@ module GtfsStopsClustering
37
43
  gtfs_stops.flatten
38
44
  end
39
45
 
40
- def clusterize_stops_csv(stops_merged)
41
- data = import_stops_data(stops_merged, @stops_config_path)
42
- @clusters = DBSCAN( data[:stops_data], data[:stops_redis_geodata], :epsilon => @epsilon, :min_points => @min_points, :similarity => @names_similarity, :distance => :haversine_distance2, :labels => data[:stops_names] )
46
+ def clusterize_stops
47
+ data = import_stops_data(@gtfs_stops, @stops_config_path)
48
+ @clusters = DBSCAN(data[:stops_data],
49
+ data[:stops_redis_geodata],
50
+ epsilon: @epsilon,
51
+ min_points: @min_points,
52
+ similarity: @names_similarity,
53
+ distance: :haversine_distance2,
54
+ labels: data[:stops_names])
55
+ map_clustered_stops
56
+ end
43
57
 
44
- @clusters.each do |cluster_id, cluster|
58
+ def map_clustered_stops
59
+ @clusters.each_value do |cluster|
45
60
  cluster.each do |stop|
46
61
  gtfs_stop = @gtfs_stops.find { |e| e.lat == stop[:stop_lat] && e.lon == stop[:stop_lon] }
47
62
  stop[:stop_id] = gtfs_stop.id
@@ -49,24 +64,11 @@ module GtfsStopsClustering
49
64
  stop[:parent_station] = gtfs_stop.parent_station
50
65
  end
51
66
  end
52
-
53
- output_path = 'stop_clusters.txt'
54
- File.open(output_path, 'w') do |file|
55
- @clusters.each do |cluster_id, cluster |
56
- file.puts "Cluster #{cluster_id}"
57
- cluster.each do |point|
58
- file.puts point.inspect
59
- end
60
- file.puts
61
- end
62
- end
63
67
  end
64
68
  end
65
69
 
66
- def build(gtfs_urls, epsilon, min_points, names_similarity = 1, stop_config_path = '')
67
- @gtfs_stops_clustering = GtfsStopsClustering.new(gtfs_urls, epsilon, min_points, names_similarity, stop_config_path)
70
+ def build_clusters(gtfs_paths, epsilon, min_points, names_similarity = 1, stop_config_path = "")
71
+ @gtfs_stops_clustering = GtfsStopsClustering.new(gtfs_paths, epsilon, min_points, names_similarity, stop_config_path)
68
72
  @gtfs_stops_clustering.clusters
69
73
  end
70
74
  end
71
-
72
- include GtfsStopsClustering
metadata CHANGED
@@ -1,29 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gtfs_stops_clustering
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
- - Visco01
7
+ - Pietro Visconti
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
11
  date: 2023-12-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: gtfs
14
+ name: csv
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.4.1
19
+ version: '3.2'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 3.2.8
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
27
  - - "~>"
25
28
  - !ruby/object:Gem::Version
26
- version: 0.4.1
29
+ version: '3.2'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 3.2.8
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: distance_measures
29
35
  requirement: !ruby/object:Gem::Requirement
@@ -39,85 +45,107 @@ dependencies:
39
45
  - !ruby/object:Gem::Version
40
46
  version: 0.0.6
41
47
  - !ruby/object:Gem::Dependency
42
- name: text
48
+ name: geocoder
43
49
  requirement: !ruby/object:Gem::Requirement
44
50
  requirements:
45
51
  - - "~>"
46
52
  - !ruby/object:Gem::Version
47
- version: '1.3'
53
+ version: '1.8'
48
54
  - - ">="
49
55
  - !ruby/object:Gem::Version
50
- version: 1.3.1
56
+ version: 1.8.2
51
57
  type: :runtime
52
58
  prerelease: false
53
59
  version_requirements: !ruby/object:Gem::Requirement
54
60
  requirements:
55
61
  - - "~>"
56
62
  - !ruby/object:Gem::Version
57
- version: '1.3'
63
+ version: '1.8'
58
64
  - - ">="
59
65
  - !ruby/object:Gem::Version
60
- version: 1.3.1
66
+ version: 1.8.2
61
67
  - !ruby/object:Gem::Dependency
62
- name: geocoder
68
+ name: gtfs
63
69
  requirement: !ruby/object:Gem::Requirement
64
70
  requirements:
65
71
  - - "~>"
66
72
  - !ruby/object:Gem::Version
67
- version: '1.8'
68
- - - ">="
69
- - !ruby/object:Gem::Version
70
- version: 1.8.2
73
+ version: 0.4.1
71
74
  type: :runtime
72
75
  prerelease: false
73
76
  version_requirements: !ruby/object:Gem::Requirement
74
77
  requirements:
75
78
  - - "~>"
76
79
  - !ruby/object:Gem::Version
77
- version: '1.8'
78
- - - ">="
79
- - !ruby/object:Gem::Version
80
- version: 1.8.2
80
+ version: 0.4.1
81
81
  - !ruby/object:Gem::Dependency
82
- name: csv
82
+ name: redis
83
83
  requirement: !ruby/object:Gem::Requirement
84
84
  requirements:
85
85
  - - "~>"
86
86
  - !ruby/object:Gem::Version
87
- version: '3.2'
87
+ version: '5.0'
88
88
  - - ">="
89
89
  - !ruby/object:Gem::Version
90
- version: 3.2.8
90
+ version: 5.0.8
91
91
  type: :runtime
92
92
  prerelease: false
93
93
  version_requirements: !ruby/object:Gem::Requirement
94
94
  requirements:
95
95
  - - "~>"
96
96
  - !ruby/object:Gem::Version
97
- version: '3.2'
97
+ version: '5.0'
98
98
  - - ">="
99
99
  - !ruby/object:Gem::Version
100
- version: 3.2.8
100
+ version: 5.0.8
101
101
  - !ruby/object:Gem::Dependency
102
- name: redis
102
+ name: text
103
103
  requirement: !ruby/object:Gem::Requirement
104
104
  requirements:
105
105
  - - "~>"
106
106
  - !ruby/object:Gem::Version
107
- version: '5.0'
107
+ version: '1.3'
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
- version: 5.0.8
110
+ version: 1.3.1
111
111
  type: :runtime
112
112
  prerelease: false
113
113
  version_requirements: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: '5.0'
117
+ version: '1.3'
118
118
  - - ">="
119
119
  - !ruby/object:Gem::Version
120
- version: 5.0.8
120
+ version: 1.3.1
121
+ - !ruby/object:Gem::Dependency
122
+ name: minitest
123
+ requirement: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - "~>"
126
+ - !ruby/object:Gem::Version
127
+ version: '5.20'
128
+ type: :development
129
+ prerelease: false
130
+ version_requirements: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - "~>"
133
+ - !ruby/object:Gem::Version
134
+ version: '5.20'
135
+ - !ruby/object:Gem::Dependency
136
+ name: pry
137
+ requirement: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - "~>"
140
+ - !ruby/object:Gem::Version
141
+ version: 0.14.2
142
+ type: :development
143
+ prerelease: false
144
+ version_requirements: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - "~>"
147
+ - !ruby/object:Gem::Version
148
+ version: 0.14.2
121
149
  description: A gem to read GTFS stops data and create clusters based on coordinates
122
150
  and stop names' similarities.
123
151
  email:
@@ -129,6 +157,7 @@ files:
129
157
  - lib/gtfs_stops_clustering.rb
130
158
  - lib/gtfs_stops_clustering/data_import.rb
131
159
  - lib/gtfs_stops_clustering/dbscan.rb
160
+ - lib/gtfs_stops_clustering/input_consistency_checks.rb
132
161
  - lib/gtfs_stops_clustering/redis_geodata.rb
133
162
  - lib/gtfs_stops_clustering/version.rb
134
163
  homepage: https://github.com/Visco01/gtfs_stops_clustering