如何将 ID 从 SQLite 数据库获取到 pandas df,其中值匹配但不匹配数据类型

How to get id's from SQLite db into pandas df where the values match but not the data types

问题

我得到一个带有日期时间信息的数据框,需要提取日期和时间,将两者存储在数据库中,取回 ID 并将 date/time 值替换为数据库 ID。

这应该是一个很常见的问题,但我找不到解决方案。

先决条件

我从这样的 API 收到一个数据帧(数据在 100 到 >100000 行之间):

data = {
        'datetime' : [
            '2022-02-23 10:00:00',
            '2022-02-23 10:05:00',
            '2022-02-23 10:10:00',
            '2022-02-23 10:20:30',
            '2022-02-23 10:42:00'],
        'temp' : [
            16.539,
            16.98,
            16.82001,
            17.03,
            17.85]
        }
df = pd.DataFrame(data)

列的数据类型是:

print(df.dtypes)
datetime     object
temp        float64

数据必须存储在 SQLite 数据库中。有一个 table 用于时间、日期和测量数据,如下所示:

CREATE TABLE Tempvalues (
            id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE,
            date_id INTEGER NOT NULL,
            time_id INTEGER NOT NULL,
            tval REAL
            );

CREATE TABLE Time (
            id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE,
            time TEXT NOT NULL UNIQUE
            );

CREATE TABLE Date (
            id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE,
            date TEXT NOT NULL UNIQUE
            );

这是我将日期和时间提取到数据框中的单独列中的方法:

df['date'] = pd.to_datetime(df['datetime']).dt.date
df['time'] = pd.to_datetime(df['datetime']).dt.time

结果:

              datetime      temp        date      time
0  2022-02-23 10:00:00  16.53900  2022-02-23  10:00:00
1  2022-02-23 10:05:00  16.98000  2022-02-23  10:05:00
2  2022-02-23 10:10:00  16.82001  2022-02-23  10:10:00
3  2022-02-23 10:20:30  17.03000  2022-02-23  10:20:30
4  2022-02-23 10:42:00  17.85000  2022-02-23  10:42:00

数据类型:

print(df.dtypes)
datetime     object
temp        float64
date         object
time         object
dtype: object      

在数据库中存储 'date' 和 'time' 列:

df[['date', 'time']].to_sql('Tempdf', conn, index=False)

更新时间和数据 tables 并删除 Tempdf table:

with conn:
    cur.execute("UPDATE Tempdf SET time=STRFTIME('%H:%M:%S', time);")
    cur.execute("INSERT OR IGNORE INTO Date (date) SELECT date FROM Tempdf;")
    cur.execute("INSERT OR IGNORE INTO Time (time) SELECT time FROM Tempdf;")
    cur.execute("DROP TABLE IF EXISTS Tempdf;")

将'date'、'time'替换成id/我试过的

到目前为止,一切正常。现在我想用数据库中的 Date.id 和 Time.id 值替换数据框中的日期和时间值。由于我不应该遍历 pandas 数据框,我认为使用 pandas 替换或映射方法来完成此任务是个好主意。但它失败了,因为数据类型不匹配:

date_date_id = dict(cur.execute("SELECT date, id FROM Date").fetchall())
time_time_id = dict(cur.execute("SELECT time, id FROM Time").fetchall())

我得到一个字符串和一个整数:

print(date_date_id)
{'2022-02-23': 1}

使用pandas映射方法:

df['date'] = df['date'].map(date_date_id)
df['time'] = df['time'].map(time_time_id)

结果:

print(df)
              datetime      temp  date  time
0  2022-02-23 10:00:00  16.53900   NaN   NaN
1  2022-02-23 10:05:00  16.98000   NaN   NaN
2  2022-02-23 10:10:00  16.82001   NaN   NaN
3  2022-02-23 10:20:30  17.03000   NaN   NaN
4  2022-02-23 10:42:00  17.85000   NaN   NaN

数据类型:

datetime     object
temp        float64
date        float64
time        float64
dtype: object    

当我尝试使用浮点数时,它按预期工作:

test_temp = {16.539 : 42, 16.98 : 42}
df['temp'] = df['temp'].map(test_temp)

结果:

              datetime  temp        date      time
0  2022-02-23 10:00:00  42.0  2022-02-23  10:00:00
1  2022-02-23 10:05:00  42.0  2022-02-23  10:05:00
2  2022-02-23 10:10:00   NaN  2022-02-23  10:10:00
3  2022-02-23 10:20:30   NaN  2022-02-23  10:20:30
4  2022-02-23 10:42:00   NaN  2022-02-23  10:42:00

所以我假设它不会替换值,因为 'date' 和 'time' 的数据类型是对象而不是字符串。

当替换值指向一个空列时,结果是一样的:

df['date_id'] = df['date'].map(date_date_id)
df['time_id'] = df['time'].map(time_time_id)

结果:

              datetime      temp        date      time  date_id  time_id
0  2022-02-23 10:00:00  16.53900  2022-02-23  10:00:00      NaN      NaN
1  2022-02-23 10:05:00  16.98000  2022-02-23  10:05:00      NaN      NaN
2  2022-02-23 10:10:00  16.82001  2022-02-23  10:10:00      NaN      NaN
3  2022-02-23 10:20:30  17.03000  2022-02-23  10:20:30      NaN      NaN
4  2022-02-23 10:42:00  17.85000  2022-02-23  10:42:00      NaN      NaN

感觉这是sql应该完全完成的任务,但是我没有做到。这会在每一行中插入相同的 id,可能是第一个匹配的:

WITH tid (t_id, t_time, df_time) AS
    (SELECT Time.id, Time.time, Tempdf.time
     FROM Tempdf
     JOIN Time
        ON Time.time=Tempdf.time)

UPDATE Tempdf
SET time_id = (SELECT t_id FROM tid WHERE t_time = df_time);

问题

抱歉,我有点迷失了。如果有任何帮助,我将不胜感激。

随着列 'date' 和 'time' 的数据类型更改为字符串,映射方法起作用。

df['date'] = df['date'].astype('str').map(date_date_id)
df['time'] = df['time'].astype('str').map(time_time_id)

但我仍然希望能回答其他问题。