如何将 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.id 和 Time.id 值放入数据框中,使其与 'date'/'time' 列的值相匹配?
-> 部分回答
我是否需要以某种方式将数据类型从对象更改为字符串?如果是,如何?
-> 已回答
这是用数据库 ID 替换数据框中的值的正确方法吗?还是我走错了路?
是否有原生的 SQLite 解决方案?
抱歉,我有点迷失了。如果有任何帮助,我将不胜感激。
随着列 'date' 和 'time' 的数据类型更改为字符串,映射方法起作用。
df['date'] = df['date'].astype('str').map(date_date_id)
df['time'] = df['time'].astype('str').map(time_time_id)
但我仍然希望能回答其他问题。
问题
我得到一个带有日期时间信息的数据框,需要提取日期和时间,将两者存储在数据库中,取回 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.id 和 Time.id 值放入数据框中,使其与 'date'/'time' 列的值相匹配? -> 部分回答
我是否需要以某种方式将数据类型从对象更改为字符串?如果是,如何? -> 已回答
这是用数据库 ID 替换数据框中的值的正确方法吗?还是我走错了路?
是否有原生的 SQLite 解决方案?
抱歉,我有点迷失了。如果有任何帮助,我将不胜感激。
随着列 'date' 和 'time' 的数据类型更改为字符串,映射方法起作用。
df['date'] = df['date'].astype('str').map(date_date_id)
df['time'] = df['time'].astype('str').map(time_time_id)
但我仍然希望能回答其他问题。