You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python实现将pandas经纬度样本数据按分类追加存入数据库

实现方案

你的场景总共有固定10000种经纬度组合,核心需求是按经纬度键追加存储savings值,不需要上重型数据库,两个落地成本极低的方案完全覆盖需求:

  • 本地单机使用:选SQLite,零服务部署,单文件存储,Python原生支持,和pandas适配度极高
  • 高频写入/多服务共享:选Redis,天然支持列表结构,追加操作原子性好,内存读写延迟极低

SQLite版实现(推荐优先用)

表结构设计

直接建单表带联合索引即可,预留sample_id字段满足追溯需求,不用做额外分表:

CREATE TABLE IF NOT EXISTS savings_records (
    lat REAL NOT NULL,
    lng REAL NOT NULL,
    savings REAL NOT NULL,
    sample_id TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 给经纬度建联合索引,查询时直接命中,10万级数据量下查询延迟毫秒级
CREATE INDEX IF NOT EXISTS idx_lat_lng ON savings_records(lat, lng);

对接pandas的读写代码

import sqlite3
import pandas as pd
from typing import Optional, List, Tuple

def write_sample(df: pd.DataFrame, sample_id: Optional[str] = None, db_path: str = "location_savings.db") -> None:
    """
    写入单份pandas样本数据
    df要求包含lat、lng、savings三列,同一份样本内的重复经纬度组合会按顺序追加存储
    """
    write_df = df.copy()
    if sample_id is not None:
        write_df["sample_id"] = sample_id
    conn = sqlite3.connect(db_path)
    try:
        # 批量写入比循环单条插入快10倍以上,40行数据写入无感知
        write_df.to_sql("savings_records", conn, if_exists="append", index=False)
    finally:
        conn.close()

def get_savings_by_location(lat: float, lng: float, with_trace: bool = False, db_path: str = "location_savings.db") -> List:
    """
    查询指定经纬度对应的savings列表
    with_trace设为True时返回结果同时带对应样本编号
    """
    conn = sqlite3.connect(db_path)
    try:
        if with_trace:
            cursor = conn.execute(
                "SELECT savings, sample_id FROM savings_records WHERE lat = ? AND lng = ? ORDER BY created_at",
                (lat, lng)
            )
            return cursor.fetchall()
        else:
            cursor = conn.execute(
                "SELECT savings FROM savings_records WHERE lat = ? AND lng = ? ORDER BY created_at",
                (lat, lng)
            )
            return [row[0] for row in cursor.fetchall()]
    finally:
        conn.close()

方案说明

  • 完全兼容同一样本内重复经纬度的场景,重复记录不会被覆盖,严格按写入顺序追加
  • 后续需要做聚合统计(比如单点位的savings均值、极值、分位数)直接写SQL即可,不需要全量拉取数据到内存计算
  • 不要用本地JSON、Python字典持久化的方式存,数据量上来之后读写性能会快速下降,还容易因为进程异常退出损坏数据

Redis版实现(适合高并发场景)

如果你的样本生成频率很高,或者需要多个进程/服务同时读写数据,换Redis即可,核心是用Redis的List结构存每个经纬度对应的savings序列:

import redis
import pandas as pd
from typing import Optional, List

# 初始化redis连接,记得开持久化避免数据丢失
r = redis.Redis(host="127.0.0.1", port=6379, db=0, decode_responses=True)

def write_sample_redis(df: pd.DataFrame, sample_id: Optional[str] = None) -> None:
    pipe = r.pipeline()
    for _, row in df.iterrows():
        redis_key = f"savings:{row['lat']}:{row['lng']}"
        if sample_id:
            # 需要追溯的话把savings和sample_id拼为字符串存储
            val = f"{row['savings']}|{sample_id}"
        else:
            val = str(row["savings"])
        # rpush是原子操作,多进程同时写不会乱序
        pipe.rpush(redis_key, val)
    pipe.execute()

def get_savings_by_location_redis(lat: float, lng: float, with_trace: bool = False) -> List:
    redis_key = f"savings:{lat}:{lng}"
    raw_data = r.lrange(redis_key, 0, -1)
    if with_trace:
        return [(float(item.split("|")[0]), item.split("|")[1]) for item in raw_data]
    else:
        return [float(item.split("|")[0]) for item in raw_data]

方案说明

  • 纯内存操作,写入和查询性能比SQLite高一个量级
  • 缺点是需要单独部署Redis服务,必须开启RDB/AOF持久化配置,否则服务重启会丢失内存数据

内容的提问来源于stack exchange,提问作者Cornelis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 05:48:09