Khóa học
Khi làm việc với dữ liệu thực tế, bạn không thể mặc định rằng tập dữ liệu đã chứa mọi thông tin thiết yếu để giải quyết dự án khoa học dữ liệu của mình. Phần lớn thời gian, bạn chỉ có thông tin một phần và cần làm giàu dữ liệu bằng các đặc trưng bổ sung.
Có thể xảy ra trường hợp tập dữ liệu có chứa địa chỉ, nhưng lại thiếu vĩ độ và kinh độ. Khi đó, bước đầu tiên để làm giàu dữ liệu là bổ sung cặp toạ độ này. Chúng ta gọi quá trình chuyển đổi một địa chỉ thành vĩ độ và kinh độ là geocoding.
Geocoding rất quan trọng trong nhiều lĩnh vực như bất động sản, tài chính và logistics. Không có kỹ thuật này, bạn sẽ không thể phân tích và trực quan hoá dữ liệu trên bản đồ. Trong hướng dẫn này, chúng ta sẽ thực hiện geocoding trong Python nhờ một thư viện “cứu cánh” có tên Geopy. Bắt đầu thôi!
Geocoding là gì?
Geocoding là một quá trình chuyển đổi địa chỉ (như "1600 Amphitheatre Parkway, Mountain View, CA") thành toạ độ địa lý (như vĩ độ 37.423021 và kinh độ -122.083739), mà bạn có thể dùng để đặt điểm đánh dấu trên bản đồ hoặc định vị bản đồ. Nói đơn giản, đó là quá trình tính toán để biến mô tả địa chỉ vật lý thành một vị trí trên bề mặt Trái Đất.
Quy trình geocoding thường liên quan đến nội suy vị trí không gian, như đường phố hoặc thửa đất, trong phạm vi địa lý của một bản đồ. Các vị trí kết quả được xuất ra dưới dạng toạ độ số, phù hợp để dùng trong phân tích không gian hoặc trực quan hoá bản đồ.
Geocoding sử dụng nhiều nguồn dữ liệu để chuyển một địa chỉ thành vị trí địa lý. Nguồn chính là cơ sở dữ liệu tham chiếu đường phố, chứa tên đường và dải số địa chỉ trong một quận hay khu vực cụ thể. Các nguồn khác gồm cơ sở dữ liệu mã bưu chính, cơ sở dữ liệu tên thành phố và cơ sở dữ liệu các địa điểm quan trọng (như công viên hay mốc danh lam).
Geocoding không chỉ là lấy toạ độ cho một địa chỉ. Nó cũng được dùng trong phân tích không gian, khai phá dữ liệu và làm sạch dữ liệu. Ví dụ, doanh nghiệp dùng geocoding để phân tích thông tin nhân khẩu học nhằm triển khai các chiến dịch tiếp thị nhắm mục tiêu hoặc tối ưu hoá tuyến giao hàng. Trong lĩnh vực an toàn công cộng, geocoding được dùng để lập bản đồ vị trí các sự cố khẩn cấp nhằm điều phối nhanh nhất lực lượng ứng cứu gần nhất.
Trong bối cảnh khoa học dữ liệu, geocoding là bước then chốt để tạo trực quan hoá địa không gian và có thể được sử dụng trong nhiều ứng dụng, như dự đoán giá bất động sản, tối ưu hoá tuyến giao hàng và lập kế hoạch ứng phó thiên tai.
Geopy là gì?

Geopy là một thư viện Python mã nguồn mở, chuyên thêm thông tin vị trí vào dữ liệu thông qua nhiều dịch vụ geocoding, như Google Maps, Open StreeMap và ArcGIS.
Bạn có thể thắc mắc vì sao không dùng trực tiếp dịch vụ geocode thay vì thư viện Python. Điểm hay của Geopy là bạn có thể tận dụng các dịch vụ geocoding này chỉ với vài dòng mã. Thực vậy, Geopy đã hiện thực sẵn lớp cho từng dịch vụ, và bạn có thể dễ dàng chuyển từ API của dịch vụ này sang dịch vụ khác.
Ví dụ dự án Geocoding thực hành
Trong bài viết này, chúng ta sẽ phân tích bộ dữ liệu Canada Museum từ Kaggle. Bộ dữ liệu cung cấp thông tin về các bảo tàng tại Canada. Tập hợp các bảo tàng này có thể hữu ích khi dự đoán giá chỗ ở Airbnb ở Toronto; ví dụ, bạn có thể nhận thấy giá thuê của một danh sách tăng lên khi nó gần hơn với các điểm thu hút như bảo tàng, nhà hàng, quán cà phê, v.v.
Hãy xem qua tập dữ liệu:
import pandas as pd
import geopy
l_cols= ['Name','Street Address','City','State','Zipcode']
df = pd.read_csv('/kaggle/input/canada-museums/museums list CAN.csv', encoding = "ISO-8859-1",usecols=l_cols)
df = df[df.City=='Toronto']
df.head()

Từ phần tổng quan này, ta thấy có các cột chứa thông tin địa chỉ, như tên bảo tàng, địa chỉ đường phố, thành phố, bang và mã bưu điện.
Ở các bước tiếp theo, chúng ta cần một cột duy nhất gộp tất cả thông tin của các cột này. Làm thế nào? Cách hiệu quả nhất để nối nhiều hơn hai cột là dùng pandas.series.str.cat(), cho phép chỉ định dấu phân tách giữa các cột:
df['Country'] = 'Canada'
l_cols_concat = ['Street Address','City','State','Zipcode','Country']
df['unique_address'] = df['Name'].str.cat(others=df[l_cols_concat], sep=',',na_rep='')
df.head()

Chúng ta có thể tạo một biến chuỗi ‘address1’ chứa địa chỉ duy nhất của hàng đầu tiên:
address1 = df['unique_address'].iloc[0]
print(address1)
# Bizune Event Gallery,452 Richmond St W,Toronto,ON,M5V 1Y1,Canada
Chúng ta sẽ dùng nó ở các bước sau để thử nghiệm các dịch vụ geocoding khác nhau trên một địa chỉ. Khi đã hiểu cách Geopy trích xuất vị trí, ta có thể mở rộng sang cả một cột của dataframe pandas. Chúng ta sẽ thử các nhà cung cấp chính sau:
- Google Maps
- OpenStreetMap
- ArcGIS
Geocoding với Google Maps API
Phương pháp phổ biến nhất để chuyển địa chỉ thành toạ độ là dùng Google Maps API.
Mặc dù Google Maps là dịch vụ trả phí, bạn sẽ được tặng $200 tín dụng miễn phí khi tạo tài khoản lần đầu.
Để truy cập dịch vụ, bạn cần tạo tài khoản mới trên Google Maps Platform. Có một hướng dẫn hay giúp bạn tạo khoá API.
GM_API_KEY = 'your_api_key'
from geopy.geocoders import GoogleV3
geolocator = GoogleV3(api_key=GM_API_KEY)
GoogleV3 là lớp được hiện thực để dùng Google Maps v3 API. Trước tiên, ta thử trích xuất vị trí từ một địa chỉ đơn lẻ:
location = geolocator.geocode(address1)
print('Latitude: '+str(location.latitude)+', Longitude: '+str(location.longitude))

Sau đó, ta có thể thử mở rộng thao tác này sang trường unique_address mà ta đã tạo trước đó.
def service_geocode(g_locator, address):
location = g_locator.geocode(address)
if location!=None:
return (location.latitude, location.longitude)
else:
return np.NaN
Ta có thể dùng apply() để áp dụng hàm cho mọi hàng của unique_address:
df['LAT_LON'] = df['unique_address'].apply(lambda x:service_geocode(geolocator,x))
df[['unique_address','LAT_LON']].head()

Geocoding với OpenStreetMap API
Vì OpenStreetMap là cơ sở dữ liệu và dự án địa lý miễn phí lớn nhất và có thể chỉnh sửa, API này miễn phí. Để định vị một địa chỉ, bạn chỉ cần cung cấp email của tài khoản OSM làm đầu vào cho lớp Nominatim, thay vì khoá API:
from geopy.geocoders import Nominatim
geolocator = Nominatim(user_agent="your_email")
location = geolocator.geocode(address1)
print(location)
# None
Đáng tiếc, vị trí trả về bởi OpenStreetMap API là None vì nó không nhận diện được địa chỉ.
Thực tế, API này gặp khó khăn khi định vị hầu hết các địa chỉ đường phố trong tập dữ liệu do không có độ phủ địa chỉ tốt ở mọi khu vực.
Vì lý do đó, chúng ta cần tạo thêm trường unique_address_osm với ít thông tin hơn:
l_cols_concat = ['City','State','Country']
df['unique_address_osm'] = df['Street Address'].str.cat(others=df[l_cols_concat], sep=',',na_rep='')
address1_osm = df['unique_address_osm'].iloc[0]
Sau đó, ta truyền địa chỉ mới và thử lại để trích xuất vĩ độ và kinh độ từ địa chỉ đường phố:
address1_osm = df['unique_address_osm'].iloc[0]
location = geolocator.geocode(address1_osm)
print('Latitude: '+str(location.latitude)+', Longitude: '+str(location.longitude))

Như trước, ta áp dụng hàm service_geocode() cho toàn bộ cột unique_address_osm:
df['LAT_LON_osm'] = df['unique_address_osm'].apply(lambda x: service_geocode(geolocator,x))
df[['unique_address_osm','LAT_LON','LAT_LON_osm']].head()

Mặc dù chúng ta không chỉ rõ tên bảo tàng, OpenStreetMap trả về toạ độ rất tương tự GoogleMapsAPI.
Geocoding với ArcGIS API
ArcGIS là phần mềm cho phép phân tích và trực quan hoá dữ liệu địa không gian. Nó cũng cung cấp các dịch vụ định vị như Google Maps và OpenStreetMap.
from geopy.geocoders import ArcGIS
geolocator_arcgis = ArcGIS()
location = geolocator_arcgis.geocode(address1)
print('Latitude: '+str(location.latitude)+', Longitude: '+str(location.longitude))

Lần này, không có vấn đề gì khi lấy cặp toạ độ. Ta có thể tiếp tục mở rộng thao tác này cho tất cả các địa chỉ:
df['LAT_LON_arcgis'] = df['unique_address'].apply(lambda x: service_geocode(geolocator_arcgis,x))
df[['unique_address','LAT_LON','LAT_LON_osm','LAT_LON_arcgis']].head()

Nhìn vào vài hàng đầu của tập dữ liệu, ta thấy cặp toạ độ thu được với ArcGIS tương tự các kết quả trước đó, chỉ có khác biệt nhỏ.
Đo khoảng cách giữa hai địa điểm
Một chức năng khác của Geopy là cho phép tính khoảng cách giữa hai điểm. Điều này thực hiện được bằng cách sử dụng khoảng cách geodesic giữa hai cặp (vĩ độ, kinh độ).
from geopy.distance import geodesic
point1 = df.LAT_LON_arcgis.iloc[0]
point2 = df.LAT_LON_arcgis.iloc[1]
distance = geodesic(point1, point2)
print('The distance between {} and {} is {} meters'.format(df.Name.iloc[0],df.Name.iloc[1],distance.meters))

Khoảng cách giữa hai bảo tàng này xấp xỉ 2 kilômét.
Kết luận
Vậy là xong! Bạn đã học ba cách khác nhau để chuyển địa chỉ thành vĩ độ và kinh độ bằng Geopy. Đây là điểm khởi đầu cho các phân tích dữ liệu địa không gian phức tạp và nâng cao hơn.
Nếu bạn muốn bắt đầu với phân tích địa không gian mà không cần viết mã, cách tốt nhất là xem hướng dẫn Làm việc với Dữ liệu Địa không gian: Hướng dẫn Phân tích trong Power BI của DataCamp.
Để xây dựng các trực quan hoá và phép tính nâng cao hơn, Tableau có thể là công cụ phù hợp với bạn. Khoá học Giới thiệu về Tableau của DataCamp sẽ giúp bạn tạo các trực quan hoá dữ liệu động và giải quyết mọi bài toán phân tích.
Nếu bạn là người hâm mộ ngôn ngữ R, đây là khoá học tuyệt vời để tạo bản đồ tương tác với leaflet. Nếu bạn trung thành với Python, hãy cân nhắc khoá Trực quan hoá dữ liệu địa không gian trong Python, giúp bạn tạo các trực quan ấn tượng bằng geopandas và folium.
