We are creating prototypes of the following algorithms:Definitions:
Notes:
Pseudocode Format: Pseudocode is sloppy Python. The general format for the walkscore function looks like this: def transit_score(location):1. Stop Counting: Count the number of transit stops within a given radius.def transit_score(location): transit_score = 0 for stop in nearby_stops: return transit_scoreSeattle: Pros: Simple as all getout. Cons: Stops farther away are not as valuable as stops nearby. Five stops right at the radius are not as valuable as five stops exactly at the query point. 2.1 Distance-penalized stop countingFind the total sum of all stops within a radius weighted to penalize stops farther away. For example, stops can count for more when they're closer:
How about this. The multiplier score is proportional to the distance to the transit stop.
This is less arbitrary, but it's backwards. Here, the farther away a stop is the higher the transitscore for that stop, whereas we've already decided that closer is better. We are limited creatures. With our finite wealth we can only buy so many lollipops. In our finite days we can only travel to the candy store so many times. The cheapness of something is proportional to the number of that thing that you can afford. Specifically: cheapness = budget / cost Let's say that that the value of a transit stop is the number of times we can reach it traveling back and forth throughout a day score_stop = time_in_day / time_stopwalk Where, given an 'overhead' that represents the fixed time cost of leaving the house (putting on your jacket and finding your keys, for example): time_stopwalk = overhead + ( distance_stop / speed_walking ) Or: score_stop = speed_walking * time_in_day * (1 / (overhead*walking_speed+distance_stop)) We can remove the constant factor speed_walking * time_day to get the pure beautiful: score_stop = 1/(D + distance_stop) With an N=1: score_stop = D/(D+distance_stop) With an N=5: The transitscore of a location would be: def transitscore(location): transit_score = 0King County: An advantage of this approach is a reduced importance of the stop query radius, as stops near the radius are of diminishing importance, the stop radius can be set fairly wide to eliminate the effect of an arbitrary query cutoff. A big problem with this approach is that it counts all stops the same regardless of their level of service. Note: this same scoring inversely proportional scoring function should be used to replace the Walk Score step function. 2.2 Distance-penalized route countingdef transitscore(location): transit_score = 0Smaller stop query area: Exactly the same as above, but with a larger query area. It bleeds out scores more. Redding, CA Note that this centralizes the transitscore toward transit hubs. 3. Distance-penalized stop service-level summingYou can think of D/(D+distance_stop) as "the number of things I can afford". Multiply that quantity by the unit value of getting the thing: value*(D/(D+distance_stop)) to get "the total value of what you can get". The question is - what heuristic can we think up that's proportional to the value of a transit stop.The number of times a stop is visited by a bus over the course of a week is an easy to calculate and decent proxy for service level. def get_stop_value(stop): stop_value = 0 for trip in trips(stop): stop_value += 1 return stop_valuedef transit_score(location): transit_score = 0 for stop in nearby_stops(location): stop_value = get_stop_value(stop) distance_penalty = D/(D+distance(location,stop)) stop_score = stop_value*distance_penalty transit_score += stop_score return transit_scoreThis can be roughly thought of as proportional to the number of trip-departures that are available to the rider from a given location. The problem now is that some trips are more valuable than others. One particular trip-departure from a stop might go nowhere or terminate at the next stop, but another trip-departure might go straight to a busy shopping center. King County ![]() Redding-area. Keep in mind, the colors are relative to the maximum in the Redding area, not to the maximum in, for example, San Francisco. 3.2 Distance-penalized route service-level summingdef get_route_value(route): transit_score = 0San Francisco, MUNI only: 4.1 Distance-penalized stop service-level summing that differentiates between train vs. busdef get_trip_value(trip):def get_stop_value(stop): stop_value = 0 for trip in trips(stop): stop_value += get_trip_value(trip) return stop_valuedef transit_score(location): transit_score = 0 for stop in nearby_stops(location): stop_value = get_stop_value(stop) distance_penalty = D/(D+distance(location,stop)) stop_score = stop_value*distance_penalty transit_score += stop_score return transit_score4.3 Distance-penalized route service-level summing that differentiates between transport modesdef get_trip_value(trip): transit_score = 04.3.1 Sigmoid Function Same as above, but uses the sigmoid function "1/(1+e^((10*x-5))) from 0 to 1" for the distance penalty. Check it out on Wolfram Alpha. Island County, WA Seattle, WA San Francisco, CA Fallof function from the literature def get_distance_penalty(d): return exp(-1.5*(d*1.609344)) #from the literature; check the 'gravity functions' page def distance_penalized_route_counting(): transit_score = 0 for route_id, route_dist in nearby_routes.items(): route_value = trip_counts[route_id] route_type_value = ROUTE_TYPE_PREFERENCE[ route_types[route_id] ] distance_penalty = get_distance_penalty(route_dist) transit_score += route_value*route_type_value*distance_penalty return transit_score The heatmap color is walkscore_gradient_color(normalize_to_100(log(transitscore))) 4.3 Distance-penalized trip-weighted (calculating the Walk Score at all stops along the way) service-level summingWe need to figure out some way to estimate the importance of a given trip. Like:def get_trip_value(origin_stop, trip): trip_value = 0 for stop_time in stop_times(trip): time_penalty = T/(T+time_arrival(trip,origin_stop,stop_time)) stop_time_value = walkscore(stop(stop_time))*time_penalty trip_value += stop_time_value return trip_valuedef get_stop_value(stop): stop_value = 0 for trip in trips(stop): stop_value += get_trip_value(stop, trip) return stop_valuedef transit_score(location): transit_score = 0 for stop in nearby_stops(location): stop_value = get_stop_value(stop) distance_penalty = D/(D+distance(location,stop)) stop_score = stop_value*distance_penalty transit_score += stop_score return transit_score6. Simple Summing of all Walk Scores within a transit shed of X minutes def transit_score(location): transit_score = 0 arrivals = get_shortest_path_tree(location, time) for arrival in arrivals: if travel_time(arrival) < time_cutoff: transit_score += walk_score( stop( arrival ) ) return transit_score7. Assign a score to each transit stop that is the sum of the Walk Scores of all stops you can reach from that stop within a given time frame. To get the score of a specific address, take the distance penalized sum of nearby transit stops.The previous approach assumed that the only locations reachable from a stop were those that share a trip. In reality one often needs to transfer to another route to reach some destination. We can account for this using the sum of the time-penalized walkscores of the soonest time of arrival from a stop as the value of that stop.def get_stop_value(stop): stop_value = 0 arrivals = get_shortest_path_tree(stop, time) for arrival in arrivals: return stop_valuedef transit_score(location): transit_score = 0 for stop in nearby_stops(location): stop_value = get_stop_value(stop) distance_penalty = D/(D+distance(location,stop)) stop_score = stop_value*distance_penalty transit_score += stop_score return transit_score>>> Matt clarifies: This is basically a summing of all the Walk Scores in a transit shed, with a penalty so that things that are further away are less valuable. The time-penalized arrival-walkscores would be determined from a one or several chosen times of day (8AM, 5PM, etc) using a trip planner, such as Graphserver. Note: This approach basically says we don't need to sum all the Walk Scores in the entire transit shed b/c the Walk Score of a stop represents this and the time penalty corrects for closer being more valuable. 8. Distance-penalized summing of the Walk Scores at each transit stop you can reach within a given timeframe from a locationThe previous proposal would end up counting a location more than once if that location could be reached from multiple stops - and they usually can. If that causes a problem, you culd simply find the sum of the time-penalized walkscores of every stop using the query point as the trip-planner origin:def transit_score(location): transit_score = 0 arrivals = get_shortest_path_tree(location, time) for arrival in arrivals: arrival_value = walk_score( stop( arrival ) ) return transit_scoreThe weakness here is that trip-planning from every point could potentially be very expensive. Dates: |

























