{"id":1335,"date":"2021-12-09T06:10:15","date_gmt":"2021-12-09T06:10:15","guid":{"rendered":"https:\/\/salarydistribution.com\/machine-learning\/2021\/12\/09\/plan-the-locations-of-green-car-charging-stations-with-an-amazon-sagemaker-built-in-algorithm\/"},"modified":"2021-12-09T06:10:15","modified_gmt":"2021-12-09T06:10:15","slug":"plan-the-locations-of-green-car-charging-stations-with-an-amazon-sagemaker-built-in-algorithm","status":"publish","type":"post","link":"https:\/\/salarydistribution.com\/machine-learning\/2021\/12\/09\/plan-the-locations-of-green-car-charging-stations-with-an-amazon-sagemaker-built-in-algorithm\/","title":{"rendered":"Plan the locations of green car charging stations with an Amazon SageMaker built-in algorithm"},"content":{"rendered":"<div id=\"\">\n<p>While the fuel economy of new gasoline or diesel-powered vehicles improves every year, green vehicles are considered even more environmentally friendly because they\u2019re powered by alternative fuel or electricity. Hybrid electric vehicles (HEVs), battery only electric vehicles (BEVs), fuel cell electric vehicles (FCEVs), hydrogen cars, and solar cars are all considered types of green vehicles.<\/p>\n<p>Charging stations for green vehicles are similar to the gas pump in a gas station. They can be fixed on the ground or wall and installed in public buildings (shopping malls, public parking lots, and so on), residential district parking lots, or charging stations. They can be based on different voltage levels and charge various types of electric vehicles.<\/p>\n<p>As a charging station vendor, you should consider many factors when building a charging station. The location of charging stations is a complicated problem. Customer convenience, urban setting, and other infrastructure needs are all important considerations.<\/p>\n<p>In this post, we use machine learning (ML) with <a href=\"https:\/\/aws.amazon.com\/sagemaker\/\" target=\"_blank\" rel=\"noopener noreferrer\">Amazon SageMaker<\/a> and <a href=\"https:\/\/aws.amazon.com\/location\/\" target=\"_blank\" rel=\"noopener noreferrer\">Amazon Location Service<\/a> to provide guidance for charging station vendors looking to choose optimal charging station locations.<\/p>\n<h2>Solution overview<\/h2>\n<p>In this solution, we focus use SageMaker training jobs to train the cluster model and a SageMaker endpoint to deploy the model. We use an Amazon Location Service display map and cluster result.<\/p>\n<p>We also use <a href=\"http:\/\/aws.amazon.com\/s3\" target=\"_blank\" rel=\"noopener noreferrer\">Amazon Simple Storage Service<\/a> (Amazon S3) to store the training data and model artifacts.<\/p>\n<p>The following figure illustrates the architecture of the solution.<br \/><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-30544\" src=\"https:\/\/d2908q01vomqb2.cloudfront.net\/f1f836cb4ea6efb2a0b1b99f41ad8b103eff4b59\/2021\/11\/10\/ao.png\" alt=\"\" width=\"1314\" height=\"936\"><\/p>\n<h2>Data preparation<\/h2>\n<p>GPS data is highly sensitive information because it can be used to track historical movement of an individual. In the following post, we use the tool <a href=\"https:\/\/github.com\/sharedstreets\/trip-simulator\/\" target=\"_blank\" rel=\"noopener noreferrer\">trip-simulator<\/a> to generate GPS data that simulates a taxi driver\u2019s driving behavior.<\/p>\n<p>We choose Nashville, Tennessee, as our location. The following script simulates 1,000 agents and generates 14 hours of driving data starting September 15, 2020, 8:00 AM:<\/p>\n<div class=\"hide-language\">\n<pre><code class=\"lang-bash\">trip-simulator \n  --config scooter \n  --pbf nash.osm.pbf \n  --graph nash.osrm \n  --agents 1000 \n  --start 1600128000000 \n  --seconds 50400 \n  --traces .\/traces.json \n  --probes .\/probes.json \n  --changes .\/changes.json \n  --trips .\/trips.json<\/code><\/pre>\n<\/p><\/div>\n<p>The preceding script generates three output files. We use changes.json. It includes car driving GPS data as well as pickup and drop off information. The file format looks like the following:<\/p>\n<div class=\"hide-language\">\n<pre><code class=\"lang-json\">{\n\t\"vehicle_id\":\"PLC-4375\",\n\t\"event_time\":1600128001000,\n\t\"event_type\":\"available\",\n\t\"event_type_reason\":\"service_start\",\n\t\"event_location\":{\n\t\t\t\t\t\"type\":\"Feature\",\n\t\t\t\t\t\"properties\":{\n\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\"geometry\":{\n\t\t\t\t\t\"type\":\"Point\",\n\t\t\t\t\t\"coordinates\":\n\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t-86.7967066040155,\n\t\t\t\t\t\t\t\t36.17115028383999\n\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t}\n}<\/code><\/pre>\n<\/p><\/div>\n<p>The field event_reason has four main values:<\/p>\n<ul>\n<li><strong>service_start<\/strong> \u2013 The driver receives a ride request, and drives to the designated location<\/li>\n<li><strong>user_pick_up<\/strong> \u2013 The driver picks up a passenger<\/li>\n<li><strong>user_drop_off<\/strong> \u2013 The driver reaches the destination and drops off the passenger<\/li>\n<li><strong>maintenance<\/strong> \u2013 The driver is not in service mode and doesn\u2019t receive the request<\/li>\n<\/ul>\n<p>In this post, we only collect the location data with the status user_pick_up and user_drop_off as the algorithm\u2019s input. In real-life situations, you should also consider features such as the passenger\u2019s information and business district information.<\/p>\n<p>Pandas is an extended library of the Python language for data analysis. The following script converts the data from JSON format to CSV format via Pandas:<\/p>\n<div class=\"hide-language\">\n<pre><code class=\"lang-python\">df=pd.read_json('.\/data\/changes.json', lines=True)\ndf_event=df.event_location.apply(pd.Series)\ndf_geo=df_event.geometry.apply(pd.Series)\ndf_coord=df_geo.coordinates.apply(pd.Series)\nresult = pd.concat([df, df_coord], axis=1)\nresult = result.drop(\"event_location\",axis = 1)\nresult.columns=[\"vehicle_id\",\"event_time\",\"event_type\",\"event_reason\",\"longitude\",\"latitude\"]\nresult.to_csv('.\/data\/result.csv',index=False,sep=',')<\/code><\/pre>\n<\/p><\/div>\n<p>The following table shows our results.<\/p>\n<p>There is noise data in the original GPS data. This includes some pickup and drop-off coordinate points being marked in the lake. The generated GPS data follows uniform distribution without considering business districts, no-stop areas, and depopulated zones. In practice, there is no standard process for data preprocessing. You can simplify the process of data preprocessing and feature engineering with <a href=\"https:\/\/aws.amazon.com\/sagemaker\/data-wrangler\/\" target=\"_blank\" rel=\"noopener noreferrer\">Amazon SageMaker Data Wrangler<\/a>.<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-large wp-image-30552\" src=\"https:\/\/d2908q01vomqb2.cloudfront.net\/f1f836cb4ea6efb2a0b1b99f41ad8b103eff4b59\/2021\/11\/10\/fig-10-1024x614.png\" alt=\"\" width=\"1024\" height=\"614\"><\/p>\n<h2>Data exploration<\/h2>\n<p>To better to observe and analyze the simulated track data, we use Amazon Location for data visualization. Amazon Location provides frontend SDKs for Android, iOS, and the web. For more information about Amazon Location, see the <a href=\"https:\/\/docs.aws.amazon.com\/location\/latest\/developerguide\/what-is.html\" target=\"_blank\" rel=\"noopener noreferrer\">Developer Guide<\/a>.<\/p>\n<p>We start by creating a map on the Amazon Location console.<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-large wp-image-30554\" src=\"https:\/\/d2908q01vomqb2.cloudfront.net\/f1f836cb4ea6efb2a0b1b99f41ad8b103eff4b59\/2021\/11\/10\/fig-11-1024x252.png\" alt=\"\" width=\"1024\" height=\"252\"><\/p>\n<p>We use the <a href=\"https:\/\/maplibre.org\/maplibre-gl-js-docs\/example\/\" target=\"_blank\" rel=\"noopener noreferrer\">MapLibre GL JS SDK<\/a> for our map display. The following script displays a map of Nashville, Tennessee, and renders a specific car\u2019s driving route (or <em>trace<\/em>) line:<\/p>\n<div class=\"hide-language\">\n<pre><code class=\"lang-bash\">async function initializeMap() {\n\/\/ load credentials and set them up to refresh\nawait credentials.getPromise();\n\n\/\/ Initialize the map\nmap = new maplibregl.Map({\ncontainer: \"map\",\ncenter:[-86.792845,36.16378],\/\/ initial map centerpoint\nzoom: 10, \/\/ initial map zoom\nstyle: mapName,\ntransformRequest,\n});\n});\n\nmap.addSource('route', {\n'type': 'geojson',\n'data': {\n'type': 'Feature',\n'properties': {},\n'geometry': {\n'type': 'LineString',\n'coordinates': [\n\t\t\t\t[-86.85009051679292,36.144774042081494],\n\t\t\t\t[-86.85001827659116,36.14473133061205],\n\t\t\t\t[-86.85004741661184,36.1446756197635],\n\t\t\t\t[-86.85007975396945,36.14465452846737],\n\t\t\t\t[-86.85005249508677,36.14469518290888]\n\t\t\t\t......\n\t\t\t\t]\n\t\t\t}\n\t\t}\n\t\t\t\t\t\t}\n\t\t\t);<\/code><\/pre>\n<\/p><\/div>\n<p>The following graph displays a taxi\u2019s 14-hour driving route.<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-large wp-image-30556\" src=\"https:\/\/d2908q01vomqb2.cloudfront.net\/f1f836cb4ea6efb2a0b1b99f41ad8b103eff4b59\/2021\/11\/10\/fig-13-1024x720.png\" alt=\"\" width=\"1024\" height=\"720\"><\/p>\n<p>The following script displays the car\u2019s route distribution:<\/p>\n<div class=\"hide-language\">\n<pre><code class=\"lang-js\">map.addSource('car-location', {\n'type': 'geojson',\n'data': {\n'type': 'FeatureCollection',\n'features': [\n{'type': 'Feature','geometry': {'type': 'Point','coordinates': [-86.79417828985571,36.1742558685242]}},\n{'type': 'Feature','geometry': {'type': 'Point','coordinates': [-86.76932509874324,36.18006513143749]}},\n......\n{'type': 'Feature','geometry': {'type': 'Point','coordinates': [-86.84082991448976,36.14558741886923]}}\n\n]\n}\n});<\/code><\/pre>\n<\/p><\/div>\n<p>The following map visualization shows our results.<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-large wp-image-30558\" src=\"https:\/\/d2908q01vomqb2.cloudfront.net\/f1f836cb4ea6efb2a0b1b99f41ad8b103eff4b59\/2021\/11\/10\/fig-14-2-1024x538.png\" alt=\"\" width=\"1024\" height=\"538\"><\/p>\n<h2>Algorithm selection<\/h2>\n<p><a href=\"https:\/\/docs.aws.amazon.com\/sagemaker\/latest\/dg\/k-means.html\" target=\"_blank\" rel=\"noopener noreferrer\">K-means<\/a> is an unsupervised learning algorithm. It attempts to find discrete groupings within data, where members of a group are as similar as possible to one another and as different as possible from members of other groups.<\/p>\n<p>SageMaker uses a modified version of the web-scale k-means clustering algorithm. Compared to the original version of the algorithm, the version SageMaker uses is more accurate. Like the original algorithm, it scales to massive datasets and delivers improvements in training time. To do this, it streams mini-batches (small, random subsets) of the training data.<\/p>\n<p>The k-means algorithm expects tabular data. In this solution, the GPS coordinate data (longitude, latitude) is the input training data. See the following code:<\/p>\n<div class=\"hide-language\">\n<pre><code class=\"lang-python\">df = pd.read_csv('.\/data\/result.csv', sep=',',header=0,usecols=['longitude','latitude'])\n\n#routine that converts the training data into protobuf format required for Sagemaker K-means.\ndef write_to_s3(bucket, prefix, channel, file_prefix, X):\nbuf = io.BytesIO()\nsmac.write_numpy_to_dense_tensor(buf, X.astype('float32'))\nbuf.seek(0)\nboto3.Session().resource('s3').Bucket(bucket).Object(os.path.join(prefix, channel, file_prefix + '.data')).upload_fileobj(buf)\n\n#prepare training training and save to S3.\ndef prepare_train_data(bucket, prefix, file_prefix, save_to_s3=True):\ntrain_data = df.as_matrix()\nif save_to_s3:\nwrite_to_s3(bucket, prefix, 'train', file_prefix, train_data)\nreturn train_data\n\n# using the dataset\ntrain_data = prepare_train_data(bucket, prefix, 'train', save_to_s3=True)\n\n# SageMaker k-means ECR images ARNs\nimages = {'us-west-2': '174872318107.dkr.ecr.us-west-2.amazonaws.com\/kmeans:latest',\n'us-east-1': '382416733822.dkr.ecr.us-east-1.amazonaws.com\/kmeans:latest',\n'us-east-2': '404615174143.dkr.ecr.us-east-2.amazonaws.com\/kmeans:latest',\n'eu-west-1': '438346466558.dkr.ecr.eu-west-1.amazonaws.com\/kmeans:latest'}\n\nimage = images[boto3.Session().region_name]<\/code><\/pre>\n<\/p><\/div>\n<h2>Train the model<\/h2>\n<p>Before you train your model, consider the following:<\/p>\n<ul>\n<li><strong>Data format<\/strong> \u2013 Both protobuf recordIO and CSV formats are supported for training. In this solution, we use protobuf format and File mode as the training data input.<\/li>\n<li><strong>EC2 instance selection<\/strong> \u2013 AWS suggests using an <a href=\"http:\/\/aws.amazon.com\/ec2\" target=\"_blank\" rel=\"noopener noreferrer\">Amazon Elastic Compute Cloud<\/a> (Amazon EC2) CPU instance when selecting the k-means algorithm. We use two ml.c5.2xlarge instances for training.<\/li>\n<li><strong>Hyperparameters<\/strong> \u2013 Hyperparameters are closely related to the dataset; you can adjust them according to the actual situation to get the best results:\n<ul>\n<li><strong>k<\/strong> \u2013 The number of required clusters (k). Because we don\u2019t know the number of clusters in advance, we train many models with different values (k).<\/li>\n<li><strong>init_method<\/strong> \u2013 The method by which the algorithm chooses the initial cluster centers. A valid value is random or kmeans++.<\/li>\n<li><strong>epochs <\/strong>\u2013 The number of passes done over the training data. We set this to 10.<\/li>\n<li><strong>mini_batch_size<\/strong> \u2013 The number of observations per mini-batch for the data iterator. We tried 50, 100, 200, 500, 800, and 1,000 in our dataset.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>We train our model with the following code. To get results faster, we start up SageMaker training job concurrently, each training jobs includes two instances. The range of <strong>k<\/strong> is between 3 and 16, and each training job will generate a model, the model artifacts are saved in S3 bucket.<\/p>\n<div class=\"hide-language\">\n<pre><code class=\"lang-python\">K = range(3,16,1) #Select different k, k increased by 1 until 15\nINSTANCE_COUNT = 2 #use two CPU instances\nrun_parallel_jobs = True #make this false to run jobs one at a time, especially if you do not want \n#create too many EC2 instances at once to avoid hitting into limits.\njob_names = []\n\n# launching jobs for all k\nfor k in K:\n    print('starting train job:' + str(k))\n    output_location = 's3:\/\/{}\/kmeans_example\/output\/'.format(bucket) + output_folder\n    print('training artifacts will be uploaded to: {}'.format(output_location))\n    job_name = output_folder + str(k)\n\n    create_training_params = \n    {\n        \"AlgorithmSpecification\": {\n            \"TrainingImage\": image,\n            \"TrainingInputMode\": \"File\"\n        },\n        \"RoleArn\": role,\n        \"OutputDataConfig\": {\n            \"S3OutputPath\": output_location\n        },\n        \"ResourceConfig\": {\n            \"InstanceCount\": INSTANCE_COUNT,\n            \"InstanceType\": \"ml.c4.xlarge\",\n            \"VolumeSizeInGB\": 20\n        },\n        \"TrainingJobName\": job_name,\n        \"HyperParameters\": {\n            \"k\": str(k),\n            \"feature_dim\": \"2\",\n          \t\"epochs\": \"100\",\n            \"init_method\": \"kmeans++\",\n            \"mini_batch_size\": \"800\"\n        },\n        \"StoppingCondition\": {\n            \"MaxRuntimeInSeconds\": 60 * 60\n        },\n            \"InputDataConfig\": [\n            {\n                \"ChannelName\": \"train\",\n                \"DataSource\": {\n                    \"S3DataSource\": {\n                        \"S3DataType\": \"S3Prefix\",\n                        \"S3Uri\": \"s3:\/\/{}\/{}\/train\/\".format(bucket, prefix),\n                        \"S3DataDistributionType\": \"FullyReplicated\"\n                    }\n                },\n\n                \"CompressionType\": \"None\",\n                \"RecordWrapperType\": \"None\"\n            }\n        ]\n    }\n\n    sagemaker = boto3.client('sagemaker')\n\n    sagemaker.create_training_job(**create_training_params)<\/code><\/pre>\n<\/p><\/div>\n<h2>Evaluate the model<\/h2>\n<p>The number of clusters (<strong>k<\/strong>) is the most important hyperparameter in k-means clustering. Because we don\u2019t know the value of <strong>k<\/strong>, we can use various methods to find the optimal value of <strong>k<\/strong>. In this section, we discuss two methods.<\/p>\n<h3>Elbow method<\/h3>\n<p>The elbow method is an empirical method to find the optimal number of clusters for a dataset. In this method, we select a range of candidate values of <strong>k<\/strong>, then apply k-means clustering using each of the values of <strong>k<\/strong>. We find the average distance of each point in a cluster to its centroid, and represent it in a plot. We select the value of <strong>k<\/strong> where the average distance falls suddenly. See the following code:<\/p>\n<div class=\"hide-language\">\n<pre><code class=\"lang-python\">plt.plot()\nmodels = {}\ndistortions = []\nfor k in K:\ns3_client = boto3.client('s3')\nkey = 'kmeans_example\/output\/' + output_folder +'\/' + output_folder + str(k) + '\/output\/model.tar.gz'\ns3_client.download_file(bucket, key, 'model.tar.gz')\nprint(\"Model for k={} ({})\".format(k, key))\n!tar -xvf model.tar.gz\nkmeans_model=mx.ndarray.load('model_algo-1')\nkmeans_numpy = kmeans_model[0].asnumpy()\nprint(kmeans_numpy)\ndistortions.append(sum(np.min(cdist(train_data, kmeans_numpy, 'euclidean'), axis=1)) \/ train_data.shape[0])\nmodels[k] = kmeans_numpy\n\n# Plot the elbow\nplt.plot(K, distortions, 'bx-')\nplt.xlabel('k')\nplt.ylabel('distortion')\nplt.title('Elbow graph')\nplt.show()<\/code><\/pre>\n<\/p><\/div>\n<p>We select a <strong>k<\/strong> range from 3\u201315 and train the model with a built-in k-means clustering algorithm. When the model is fit with 10 clusters, we can see an elbow shape in the graph. This is an optimal cluster number.<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-30560\" src=\"https:\/\/d2908q01vomqb2.cloudfront.net\/f1f836cb4ea6efb2a0b1b99f41ad8b103eff4b59\/2021\/11\/10\/fig-80-2.png\" alt=\"\" width=\"1000\" height=\"643\"><\/p>\n<h3>Silhouette method<\/h3>\n<p>The silhouette method is another method to find the optimal number of clusters and interpretation and validation of consistency within clusters of data. The silhouette method computes silhouette coefficients of each point that measure how much a point is similar to its own cluster compared to other clusters by providing a succinct graphical representation of how well each object has been classified.<\/p>\n<p>The silhouette value is a measure of how similar an object is to its own cluster (cohesion) compared to other clusters (separation). The value of the silhouette ranges between [1, -1], where a high value indicates that the object is well matched to its own cluster and poorly matched to neighboring clusters. If most objects have a high value, then the clustering configuration is appropriate. If many points have a low or negative value, then the clustering configuration may have too many or too few clusters.<\/p>\n<p>First, we must deploy the model and predict the y value as silhouette input:<\/p>\n<div class=\"hide-language\">\n<pre><code class=\"lang-python\">import json\nruntime = boto3.Session().client('runtime.sagemaker')\nendpointName=\"kmeans-30-2021-08-06-00-48-38-963\"\nresponse = runtime.invoke_endpoint(EndpointName=endpointName,\nContentType='text\/csv',\nBody=b\"-86.77971153,36.16336978n-86.77971153,36.16336978\")\nr=response['Body'].read()\nresponse_json = json.loads(r)\ny_km=[]\nfor item in response_json['predictions']:\ny_km.append(int(item['closest_cluster']))<\/code><\/pre>\n<\/p><\/div>\n<p>Next, we call the silhouette:<\/p>\n<div class=\"hide-language\">\n<pre><code class=\"lang-python\">import numpy as np\nfrom matplotlib import cm\nimport matplotlib.pyplot as plt\nfrom sklearn.metrics import silhouette_score,silhouette_samples\n\ncluster_labels=np.unique(y_km)\nprint(cluster_labels)\nn_clusters=cluster_labels.shape[0]\nsilhouette_score_cluster_10=silhouette_score(X, y_km)\nprint(\"Silhouette Score When Cluster Number Set to 10: %.3f\" % silhouette_score_cluster_10)\nsilhouette_vals=silhouette_samples(X,y_km,metric='euclidean')\ny_ax_lower,y_ax_upper=0,0\nyticks=[]\nfor i,c in enumerate(cluster_labels):\nc_silhouette_vals=silhouette_vals[y_km==c]\nc_silhouette_vals.sort()\ny_ax_upper+=len(c_silhouette_vals)\ncolor=cm.jet(float(i)\/n_clusters)\nplt.barh(range(y_ax_lower,y_ax_upper),\nc_silhouette_vals,\nheight=1.0,\nedgecolor='none',\ncolor=color)\nyticks.append((y_ax_lower+y_ax_upper)\/2.0)\ny_ax_lower+=len(c_silhouette_vals)\n\nsilhouette_avg=np.mean(silhouette_vals)\nplt.axvline(silhouette_avg,\ncolor='red',\nlinestyle='--')\nplt.yticks(yticks,cluster_labels+1)\nplt.ylabel(\"Cluster\")\nplt.xlabel(\"Silhouette Coefficients k=10,Score=%.3f\" % silhouette_score_cluster_10)\nplt.savefig('.\/figure.png')\nplt.show()<\/code><\/pre>\n<\/p><\/div>\n<p>When the silhouette score is closer to 1, it means clusters are well apart from each other. In the following experiment result, when <strong>k<\/strong> is set to 8, each cluster is well apart from each other.<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-large wp-image-30561\" src=\"https:\/\/d2908q01vomqb2.cloudfront.net\/f1f836cb4ea6efb2a0b1b99f41ad8b103eff4b59\/2021\/11\/10\/fig-81-3-1024x624.png\" alt=\"\" width=\"1024\" height=\"624\"><\/p>\n<p>We can use different model evaluation methods to get different values for the best k. In our experiment, we choose k=10 as optimal clusters.<\/p>\n<p>Now we can display the k-means clustering result via Amazon Location. The following code marks selected locations on the map:<\/p>\n<div class=\"hide-language\">\n<pre><code class=\"lang-js\">new maplibregl.Marker().setLngLat([-86.755974, 36.19235]).addTo(map);\nnew maplibregl.Marker().setLngLat([-86.710972, 36.203389]).addTo(map);\nnew maplibregl.Marker().setLngLat([-86.733895, 36.150209]).addTo(map);\nnew maplibregl.Marker().setLngLat([-86.795974, 36.165639]).addTo(map);\nnew maplibregl.Marker().setLngLat([-86.786743, 36.222799]).addTo(map);\nnew maplibregl.Marker().setLngLat([-86.701209, 36.267679]).addTo(map);\nnew maplibregl.Marker().setLngLat([-86.820134, 36.209863]).addTo(map);\nnew maplibregl.Marker().setLngLat([-86.769743, 36.131246]).addTo(map);\nnew maplibregl.Marker().setLngLat([-86.803346, 36.142358]).addTo(map);\nnew maplibregl.Marker().setLngLat([-86.833890, 36.113466]).addTo(map);<\/code><\/pre>\n<\/p><\/div>\n<p>The following map visualization shows our results, with 10 clusters.<br \/><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-large wp-image-30583\" src=\"https:\/\/d2908q01vomqb2.cloudfront.net\/f1f836cb4ea6efb2a0b1b99f41ad8b103eff4b59\/2021\/11\/10\/fig-90-2-1024x753.png\" alt=\"\" width=\"1024\" height=\"753\"><br \/>We also need to consider the scale of the charging station. Here, we divide the number of points around the center of each cluster by a coefficient (for example, the coefficient value is 100, which means every 100 cars share a charger pile). The following visualization includes charging station scale.<br \/><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-large wp-image-30584\" src=\"https:\/\/d2908q01vomqb2.cloudfront.net\/f1f836cb4ea6efb2a0b1b99f41ad8b103eff4b59\/2021\/11\/10\/fig-92-1-1024x681.png\" alt=\"\" width=\"1024\" height=\"681\"><\/p>\n<h2>Conclusion<\/h2>\n<p>In this post, we explained an end-to-end scenario for creating a clustering model in SageMaker based on simulated driving data. The solution includes training an MXNet model and creating an endpoint for real-time model hosting. We also explained how you can display the clustering results via the Amazon Location SDK.<\/p>\n<p>You should also consider charging type and quantity. Plug-in charging is categorized by voltage and power levels, leading to different charging times. Slow charging usually takes several hours to charge, whereas fast charging can achieve a 50% charge in 10\u201315 minutes. We cover these factors in a later post.<\/p>\n<p>Many other industries are also affected by location planning problems, including retail stores and warehouses. If you have feedback about this post, submit comments in the <strong>Comments<\/strong> section below.<\/p>\n<hr>\n<h3>About the Author<\/h3>\n<p><a href=\"https:\/\/d2908q01vomqb2.cloudfront.net\/f1f836cb4ea6efb2a0b1b99f41ad8b103eff4b59\/2021\/11\/16\/zz-1.png\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-30800 size-full alignleft\" src=\"https:\/\/d2908q01vomqb2.cloudfront.net\/f1f836cb4ea6efb2a0b1b99f41ad8b103eff4b59\/2021\/11\/16\/zz-1.png\" alt=\"\" width=\"100\" height=\"134\"><\/a><strong>Zhang Zheng<\/strong> is a Sr. Partner Solutions Architect with AWS, helping industry partners on their journey to well-architected machine learning solutions at scale.<\/p>\n<p>       <!-- '\"` -->\n      <\/div>\n","protected":false},"excerpt":{"rendered":"<p>https:\/\/aws.amazon.com\/blogs\/machine-learning\/plan-the-locations-of-green-car-charging-stations-with-an-amazon-sagemaker-built-in-algorithm\/<\/p>\n","protected":false},"author":0,"featured_media":1336,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[3],"tags":[],"_links":{"self":[{"href":"https:\/\/salarydistribution.com\/machine-learning\/wp-json\/wp\/v2\/posts\/1335"}],"collection":[{"href":"https:\/\/salarydistribution.com\/machine-learning\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/salarydistribution.com\/machine-learning\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/salarydistribution.com\/machine-learning\/wp-json\/wp\/v2\/comments?post=1335"}],"version-history":[{"count":0,"href":"https:\/\/salarydistribution.com\/machine-learning\/wp-json\/wp\/v2\/posts\/1335\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/salarydistribution.com\/machine-learning\/wp-json\/wp\/v2\/media\/1336"}],"wp:attachment":[{"href":"https:\/\/salarydistribution.com\/machine-learning\/wp-json\/wp\/v2\/media?parent=1335"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/salarydistribution.com\/machine-learning\/wp-json\/wp\/v2\/categories?post=1335"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/salarydistribution.com\/machine-learning\/wp-json\/wp\/v2\/tags?post=1335"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}