हर संगठन जो कुछ वर्षों से अधिक समय से पता डेटा एकत्र कर रहा है, उसके पास एक ही समस्या है: अज्ञात गुणवत्ता वाली एक बड़ी, गड़बड़ पता तालिका। वेब फॉर्म के माध्यम से प्रविष्ट पते जहां उपयोगकर्ता ध्यान नहीं दे रहे थे। पुरानी CRM से माइग्रेट किए गए रिकॉर्ड जिन्होंने इनपुट को वैलिडेट नहीं किया। एक साथी की Excel शीट से बल्क आयात जो असंगत प्रारूप में है। व्यावसायिक स्थान जो डेटा एकत्र होने के बाद से स्थानांतरित हो गई हैं।
खराब पता डेटा पर लॉजिस्टिक्स चलाने से डिलीवरी विफल हो जाती है। इसके लिए विपणन चलाने से सीधे मेल खर्च बर्बाद होता है। इसके लिए रीयल एस्टेट मूल्यांकन चलाने से अनुचित समूह क्षेत्र विश्लेषण होता है। इन संचालनों में से कोई भी होने से पहले, पते को साफ किया जाना चाहिए और मान्य किया जाना चाहिए।
Geocoding इसे पैमाने पर करने का सबसे प्रभावी तरीका है। Geocoding API को एक कच्चा पता स्ट्रिंग भेजें, संरचित घटक, भौगोलिक निर्देशांक और एक विश्वास स्कोर वापस प्राप्त करें। पते जो उच्च विश्वास के साथ अच्छी तरह geocode करते हैं, लगभग निश्चित रूप से मान्य हैं। पते जो कम विश्वास या कोई मेल नहीं लौटाते हैं, उन्हें मानव समीक्षा की आवश्यकता है।
यह ट्यूटोरियल एक संपूर्ण Python स्क्रिप्ट बनाता है जो पते की एक CSV को पढ़ता है, MapAtlas Geocoding API के विरुद्ध प्रत्येक को geocode करता है, विश्वास स्कोर के साथ परिणाम लिखता है, और कम विश्वास वाले रिकॉर्ड को मैनुअल समीक्षा के लिए फ्लैग करता है। यह दर सीमा, क्षणिक नेटवर्क त्रुटि और EU पता प्रारूप की विचित्रताओं को संभालता है जिन्हें अमेरिका-केंद्रित geocoding ट्यूटोरियल मिस करते हैं।
पता डेटा गलत क्यों हो जाता है
पता गुणवत्ता अनुमानित कारणों से कम हो जाती है:
मैनुअल प्रविष्टि त्रुटियां। वेब फॉर्म उपयोगकर्ता जल्दी टाइप करते हैं, स्वतः सुधार सड़क के नामों को विकृत करता है, और वह सत्यापन जो कोई भी गैर-खाली स्ट्रिंग स्वीकार करता है कचरा को आने देता है। B2C चेकआउट डेटा का एक अध्ययन पाया कि 7-12% मैनुअली प्रविष्ट पते में त्रुटियां हैं जो डिलीवरी विफलता का कारण बनने के लिए काफी महत्वपूर्ण हैं।
व्यावसायिक पुनर्स्थापन। एक B2B डेटाबेस जो दो साल पहले एकत्र किया गया था, उसके पास लगभग 10-15% पते होंगे जो चालें, विलय और बंद होने के कारण वर्तमान व्यावसायिक स्थान से मेल नहीं खाते।
प्रारूप असंगतियां। कई स्रोतों से एकत्र डेटा विभिन्न सम्मेलन का उपयोग करता है: पूर्ण देश के नाम बनाम ISO कोड, "सेंट।" बनाम "सड़क," घर-संख्या-पहले-सड़क बनाम बाद, "अपार्टमेंट" बनाम "apt" बनाम "wohnung"। एक geocoder इन सभी को संरचित आउटपुट में सामान्य करता है।
विरासत प्रणाली प्रवास। पता फ़ील्ड जो कई डेटाबेस स्तंभों में विभाजित थे, अक्सर माइग्रेशन के दौरान जोड़े जाते हैं, संरचना खो जाती है। पुरानी प्रणालियों से मुक्त-पाठ पता फ़ील्ड में नोट्स, संदर्भ या स्वरूपण हो सकते हैं जो वास्तविक पता का हिस्सा नहीं है।
Geocoding दृष्टिकोण इन सभी को संभालता है क्योंकि यह भौगोलिक मिलान पर निर्भर करता है, स्ट्रिंग मिलान पर नहीं। एक पता जो गलत तरीके से स्वरूपित है, फिर भी सही तरीके से geocode हो सकता है यदि अंतर्निहित स्थान डेटा मेल खाता है।
विश्वास स्कोर को समझना
MapAtlas Geocoding API प्रत्येक सुविधा पर एक confidence संपत्ति लौटाता है, जो 0.0 से 1.0 तक है। यह दर्शाता है कि लौटाया गया परिणाम इनपुट क्वेरी से कितनी घनिष्ठता से मेल खाता है, प्रारूप अंतर, संक्षिप्ताक्षर और अस्पष्टता के लिए लेखांकन।
| विश्वास | व्याख्या | अनुशंसित कार्रवाई |
|---|---|---|
| 0.90 – 1.00 | सटीक या लगभग-सटीक मिलान | स्वचालित रूप से स्वीकार करें |
| 0.85 – 0.89 | मजबूत मिलान, मामूली प्रारूप अंतर | लॉगिंग के साथ स्वीकार करें |
| 0.60 – 0.84 | आंशिक मिलान, सड़क पाई गई लेकिन घर संख्या अनिश्चित | मैनुअल समीक्षा के लिए फ्लैग करें |
| 0.40 – 0.59 | अस्पष्ट, स्थान मिलान किया गया लेकिन विशिष्ट पता नहीं | अस्वीकार या बढ़ाएं |
| 0.00 – 0.39 | कोई सार्थक मिलान नहीं | अस्वीकार करें, संभवतः अमान्य |
ये सीमाएं प्रारंभिक बिंदु हैं। एक लॉजिस्टिक्स ऑपरेशन के लिए जहां विफल डिलीवरी महंगी है, स्वचालित-स्वीकार सीमा को 0.92+ तक कसें। विपणन मेलिंग सूची के लिए जहां मैनुअल समीक्षा की लागत कुछ खराब पते की लागत से अधिक है, इसे 0.80 तक ढीला करें।
API एक match_type संपत्ति भी लौटाता है जो दर्शाता है कि पता पदानुक्रम के किस स्तर से मेल खाया गया: point (सटीक भवन), interpolated (ज्ञात घर संख्याओं के बीच का आकलन किया गया), street (सड़क पाई गई लेकिन घर संख्या नहीं) या locality (केवल शहर मिला)।
Python सत्यापन स्क्रिप्ट
Install dependencies:
pip install requests pandas tqdm
The script reads a CSV with an address column (or separate street, city, country columns), geocodes each row, and writes a new CSV with validation results appended.
#!/usr/bin/env python3
"""
bulk_geocode.py, Validate a CSV of addresses using the MapAtlas Geocoding API.
Input CSV must have either:
- An 'address' column (full address string), or
- 'street', 'city', and 'country' columns (will be concatenated)
Outputs a new CSV with added columns:
geocoded_label, geocoded_lat, geocoded_lng, confidence, match_type, status
"""
import csv
import time
import logging
import requests
import pandas as pd
from tqdm import tqdm
from pathlib import Path
# ── Configuration ──────────────────────────────────────────────────────────────
API_KEY = 'YOUR_API_KEY'
API_BASE = 'https://api.mapatlas.eu/geocoding/v1/search'
INPUT_CSV = 'addresses.csv'
OUTPUT_CSV = 'addresses_validated.csv'
RATE_LIMIT_RPS = 5 # Requests per second (stay within your plan limits)
RETRY_ATTEMPTS = 3 # Retries on transient errors
RETRY_DELAY_S = 2.0 # Seconds between retries
# Confidence thresholds
ACCEPT_THRESHOLD = 0.85
REVIEW_THRESHOLD = 0.60
logging.basicConfig(level=logging.INFO, format='%(levelname)s %(message)s')
log = logging.getLogger(__name__)
# ── Geocoding function ─────────────────────────────────────────────────────────
def geocode_address(address_str: str) -> dict:
"""
Geocode a single address string. Returns a dict with result fields.
Retries on network errors and 429 rate-limit responses.
"""
params = {
'text': address_str,
'key': API_KEY,
'size': 1,
}
for attempt in range(RETRY_ATTEMPTS):
try:
resp = requests.get(API_BASE, params=params, timeout=10)
if resp.status_code == 429:
# Rate limited, wait and retry
wait = float(resp.headers.get('Retry-After', RETRY_DELAY_S * (attempt + 1)))
log.warning(f'Rate limited. Waiting {wait:.1f}s before retry {attempt + 1}.')
time.sleep(wait)
continue
resp.raise_for_status()
data = resp.json()
if not data.get('features'):
return {'geocoded_label': '', 'geocoded_lat': None, 'geocoded_lng': None,
'confidence': 0.0, 'match_type': 'no_match', 'status': 'reject'}
feature = data['features'][0]
props = feature['properties']
coords = feature['geometry']['coordinates'] # [lng, lat]
confidence = round(float(props.get('confidence', 0.0)), 4)
match_type = props.get('match_type', 'unknown')
if confidence >= ACCEPT_THRESHOLD:
status = 'accept'
elif confidence >= REVIEW_THRESHOLD:
status = 'review'
else:
status = 'reject'
return {
'geocoded_label': props.get('label', ''),
'geocoded_lat': round(coords[1], 6),
'geocoded_lng': round(coords[0], 6),
'confidence': confidence,
'match_type': match_type,
'status': status,
}
except requests.exceptions.RequestException as exc:
log.warning(f'Network error on attempt {attempt + 1}: {exc}')
if attempt < RETRY_ATTEMPTS - 1:
time.sleep(RETRY_DELAY_S * (attempt + 1))
# All retries exhausted
return {'geocoded_label': '', 'geocoded_lat': None, 'geocoded_lng': None,
'confidence': 0.0, 'match_type': 'error', 'status': 'error'}
# ── Main processing loop ───────────────────────────────────────────────────────
def main():
df = pd.read_csv(INPUT_CSV, dtype=str).fillna('')
# Build address string from available columns
if 'address' in df.columns:
df['_query'] = df['address']
elif all(c in df.columns for c in ['street', 'city', 'country']):
df['_query'] = df['street'] + ', ' + df['city'] + ', ' + df['country']
else:
raise ValueError("CSV must have 'address' or 'street'+'city'+'country' columns.")
results = []
sleep_interval = 1.0 / RATE_LIMIT_RPS
for query in tqdm(df['_query'], desc='Geocoding', unit='addr'):
result = geocode_address(query.strip())
results.append(result)
time.sleep(sleep_interval)
results_df = pd.DataFrame(results)
output_df = pd.concat([df.drop(columns=['_query']), results_df], axis=1)
output_df.to_csv(OUTPUT_CSV, index=False, quoting=csv.QUOTE_NONNUMERIC)
# Summary
total = len(output_df)
accept = (output_df['status'] == 'accept').sum()
review = (output_df['status'] == 'review').sum()
reject = (output_df['status'] == 'reject').sum()
errors = (output_df['status'] == 'error').sum()
log.info(f'\n── Results ────────────────────────────────')
log.info(f'Total processed : {total:,}')
log.info(f'Accept (≥{ACCEPT_THRESHOLD}) : {accept:,} ({accept/total:.1%})')
log.info(f'Review : {review:,} ({review/total:.1%})')
log.info(f'Reject : {reject:,} ({reject/total:.1%})')
log.info(f'Errors : {errors:,} ({errors/total:.1%})')
log.info(f'Output written to {OUTPUT_CSV}')
if __name__ == '__main__':
main()
इसे चलाएं:
python bulk_geocode.py
10,000-पता CSV के लिए 5 अनुरोध/सेकंड पर, स्क्रिप्ट लगभग 35 मिनट में पूरी हो जाती है। प्रगति पट्टी (tqdm के माध्यम से) वास्तविक समय थ्रूपुट और अनुमानित समापन समय दिखाती है।
आउटपुट को संभालना
आउटपुट CSV आपके इनपुट डेटा में छह कॉलम जोड़ता है:
address, ..., geocoded_label, geocoded_lat, geocoded_lng, confidence, match_type, status
तीन आउटपुट फ़ाइलें बनाने के लिए स्थिति द्वारा फ़िल्टर करें:
# main() चलाने के बाद, स्वीकृति स्तरों में विभाजित करें:
df = pd.read_csv('addresses_validated.csv')
df[df['status'] == 'accept'].to_csv('addresses_clean.csv', index=False)
df[df['status'] == 'review'].to_csv('addresses_review.csv', index=False)
df[df['status'] == 'reject'].to_csv('addresses_reject.csv', index=False)
print(f"Clean: {len(df[df['status']=='accept']):,} पते उपयोग के लिए तैयार")
print(f"Review: {len(df[df['status']=='review']):,} पते मैनुअल जांच के लिए")
print(f"Reject: {len(df[df['status']=='reject']):,} पते हटाने या ठीक करने के लिए")
addresses_review.csv फ़ाइल वह है जिसे मानव ध्यान की आवश्यकता है। विशिष्ट समीक्षा पैटर्न:
- मेल प्रकार
street(विश्वास 0.65–0.80): सड़क पाई गई लेकिन घर संख्या नहीं। संभवतः एक नई इमारत, विरल कवरेज वाला ग्रामीण पता, या घर संख्या में टाइपो। मूल स्रोत की जाँच करें। - मेल प्रकार
locality(विश्वास 0.50–0.65): केवल शहर मिला। सड़क का नाम संभवतः गलत तरीके से लिखा गया है या डेटा में मौजूद नहीं है। डाक निर्देशिका में पते को देखें। - स्पष्ट रूप से मान्य दिखने वाले पते पर कम विश्वास: देश/भाषा मिलान की जांच करें। बिना देश प्रतिबंध के क्वेरी किया गया डच पता समान नाम वाले जर्मन या बेल्जियम शहर के विरुद्ध geocode हो सकता है।
EU पता विचित्रताएं जानने के लिए
अमेरिका के बाजार के लिए लिखी गई बल्क geocoding गाइडें प्रारूप अंतर को छोड़ देती हैं जो EU डेटासेट को परेशान करते हैं। यहाँ सबसे आम समस्याएं हैं:
जर्मनी, घर संख्या ऑर्डर। जर्मन पते {street} {number} प्रारूप का उपयोग करते हैं: Berliner Straße 42। कई CRM पते को {number} {street} प्रारूप में संग्रहीत करते हैं क्योंकि वे UK/US सम्मेलन के लिए बनाए गए थे। यदि आपके जर्मन पते कम विश्वास के साथ geocoding कर रहे हैं, तो क्वेरी स्ट्रिंग में संख्या और सड़क का नाम उलट करने का प्रयास करें।
फ्रांस, arrondissements। पेरिस के पते में एक arrondissement (1st–20th) डाक कोड के भाग के रूप में शामिल है: 75001 से 75020। क्वेरी जो arrondissement को छोड़ देती है और केवल Paris का उपयोग करती है, शहर के केंद्रीय बिंदु के लिए geocoded होती हैं, विशिष्ट जिला नहीं, यह address मेल के बजाय कम विश्वास के साथ locality मेल के रूप में दिखाई देता है।
नीदरलैंड, डाक कोड प्रारूप। डच डाक कोड सख्त DDDD LL पैटर्न का अनुसरण करते हैं (4 अंक, स्थान, 2 बड़े अक्षर)। बिना स्थान के संग्रहीत कोड (1012LG के बजाय 1012 LG) या छोटे अक्षर के साथ सही तरीके से geocode होंगे, लेकिन यदि आप अलग से डाक कोड प्रारूप को मान्य कर रहे हैं, तो बड़े अक्षर के साथ स्थान में सामान्य करें।
बेल्जियम, भाषा अस्पष्टता। कुछ बेल्जियम नगर पालिकाओं के विभिन्न फ्रेंच और डच नाम हैं (Liège/Luik, Gent/Gand)। API दोनों को संभालता है, लेकिन आपके डेटासेट में असंगत नामकरण (कुछ रिकॉर्ड फ्रेंच का उपयोग कर रहे हैं, कुछ डच) विभिन्न विश्वास स्तर उत्पन्न कर सकते हैं। Geocoding से पहले प्रति क्षेत्र एक भाषा को सामान्य करें।
स्पेन और इटली, सड़क उपसर्ग भिन्नताएं। "Calle", "Carrer", "Via", "Viale" सभी मान्य सड़क प्रकार उपसर्ग हैं और रिकॉर्ड में संक्षिप्त हो सकते हैं ("C/")। Geocoder सामान्य संक्षिप्ताक्षर को संभालता है लेकिन विरासत प्रणालियों से असामान्य छोटी करने के लिए एक सामान्यकरण चरण की आवश्यकता हो सकती है।
समवर्ती अनुरोधों के साथ थ्रूपुट बढ़ाना
अनुक्रमिक स्क्रिप्ट सुरक्षित और सरल है लेकिन धीमी है। बड़े डेटासेट के लिए, अनुक्रमिक लूप को एक समवर्ती निष्पादक के साथ बदलें:
from concurrent.futures import ThreadPoolExecutor, as_completed
def main_concurrent(max_workers=10):
df = pd.read_csv(INPUT_CSV, dtype=str).fillna('')
# ... (पहले जैसा सेटअप) ...
results = [None] * len(df)
with ThreadPoolExecutor(max_workers=max_workers) as executor:
future_to_idx = {
executor.submit(geocode_address, row['_query'].strip()): idx
for idx, row in df.iterrows()
}
for future in tqdm(as_completed(future_to_idx), total=len(df), desc='Geocoding'):
idx = future_to_idx[future]
results[idx] = future.result()
# ... (पहले जैसे आउटपुट लेखन) ...
10 समवर्ती कार्यकर्ताओं के साथ 5 RPS प्रति कार्यकर्ता पर, थ्रूपुट लगभग 50 अनुरोध/सेकंड तक पहुंचता है, 10,000 पते 4 मिनट में। max_workers बढ़ाने से पहले अपनी MapAtlas योजना की समवर्ती अनुरोध सीमा की जांच करें।
उन संगठनों के लिए जो एक आवर्ती संचालन के रूप में पता सत्यापन चलाते हैं, साप्ताहिक नई CRM आयात सफाई कर रहे हैं, या रात में डिलीवरी पते को मान्य कर रहे हैं, Logistics & Delivery समाधान पृष्ठ देखें कि कैसे MapAtlas एकीकरण कार्यप्रवाह में फिट होते हैं।
यदि आप पता स्वतः पूर्ण बनाने के लिए बनाते हैं ताकि खराब डेटा पहले स्थान पर आपके सिस्टम में प्रवेश न करे (त्रुटियों को बैच में सफाई करने के बजाय स्रोत पर पकड़ना), Address Autocomplete API: How One Field Lifts Checkout Conversion by 35% फ्रंटएंड कार्यान्वयन को कवर करता है।
समन्वय आउटपुट के साथ काम करना
मान्य आउटपुट प्रत्येक स्वीकृत पते के लिए geocoded_lat और geocoded_lng शामिल करता है। ये निर्देशांक विश्लेषण क्षमताओं को खोलते हैं जो कच्चे पता तारों के साथ संभव नहीं थे:
- दूरी गणनाएं। गोदाम और प्रत्येक डिलीवरी पते के बीच सीधी-रेखा दूरी की गणना करें, शिपिंग लागत स्तरों का अनुमान लगाने के लिए।
- समूह क्षेत्र विश्लेषण। मान्य ग्राहक स्थानों को मानचित्र पर प्लॉट करें यह देखने के लिए कि मांग भौगोलिक रूप से कहां केंद्रित है।
- डिलीवरी क्षेत्र असाइनमेंट। प्रत्येक पते को एक डिलीवरी क्षेत्र में असाइन करें यह परीक्षण करके कि क्या इसके निर्देशांक एक क्षेत्र बहुभुज के भीतर गिरते हैं।
- डुप्लिकेट पहचान। एक ही निर्देशांक वाले दो रिकॉर्ड (कुछ मीटर के भीतर) संभवतः डुप्लिकेट हैं, भले ही पता तार प्रारूप में भिन्न हों।
NAP (नाम/पता/फोन) सामंजस्य और AI खोज दृश्यता पर इसके प्रभाव के लिए, विशेष रूप से स्थानीय व्यावसायिक पता डेटाबेस के लिए प्रासंगिक, NAP Consistency for AI Search: Why Mismatched Addresses Kill Your ChatGPT Visibility समझाता है कि क्यों geocoding-मान्य पते संरचित डेटा मार्कअप के लिए सही आधार हैं।
सारांश
MapAtlas Geocoding API के साथ बल्क geocoding आपको देता है:
- मान्य पते विश्वास स्कोर के साथ ताकि आप जान सकें कि कौन से रिकॉर्ड को स्वचालित रूप से विश्वास करें और किन्हें समीक्षा की आवश्यकता है।
- संरचित घटक (सड़क, घर संख्या, डाक कोड, शहर, देश) किसी भी इनपुट प्रारूप से सामान्य।
- भौगोलिक निर्देशांक प्रत्येक स्वीकृत पते के लिए, स्थानिक विश्लेषण और रूटिंग को सक्षम करता है।
- EU पता प्रारूप समर्थन API में निर्मित, कुछ ऐसा नहीं जिसे आपको पूर्व-प्रसंस्करण में संभालने की आवश्यकता है।
Python स्क्रिप्ट अनुक्रमिक रूप से 5 पते/सेकंड पर चलती है, समवर्ती कार्यकर्ताओं के साथ 50/सेकंड तक। 10,000 पते के लिए, समय सामर्थ्य 4-40 मिनट बजट करें। आउटपुट तीन स्तरों के साथ एक स्वच्छ CSV है: स्वीकार करें, समीक्षा करें, अस्वीकार करें।
Sign up for a free MapAtlas API key to start. The Geocoding API supports bulk queries on all plans, see pricing for per-request rates and monthly free tier limits.

