【发布时间】:2017-03-26 15:28:23
【问题描述】:
设置
两个表:schools 和 students。 SQLite 中的索引(或键)对于students 表将是id 和time,对于schools 表将是school 和time。我的数据集是关于不同的东西,但我认为学生的例子更容易理解。
import pandas as pd
import numpy as np
import sqlite3
df_students = pd.DataFrame(
{'id': list(range(0,4)) + list(range(0,4)),
'time': [0]*4 + [1]*4, 'school': ['A']*2 + ['B']*2 + ['A']*2 + ['B']*2,
'satisfaction': np.random.rand(8)} )
df_students.set_index(['id', 'time'], inplace=True)
satisfaction school
id time
0 0 0.863023 A
1 0 0.929337 A
2 0 0.705265 B
3 0 0.160457 B
0 1 0.208302 A
1 1 0.029397 A
2 1 0.266651 B
3 1 0.646079 B
df_schools = pd.DataFrame({'school': ['A']*2 + ['B']*2, 'time': [0]*2 + [1]*2, 'mean_scores': np.random.rand(4)})
df_schools.set_index(['school', 'time'], inplace=True)
df_schools
mean_scores
school time
A 0 0.358154
A 0 0.142589
B 1 0.260951
B 1 0.683727
## Send to SQLite3
conn = sqlite3.connect('schools_students.sqlite')
df_students.to_sql('students', conn)
df_schools.to_sql('schools', conn)
我需要做什么?
我有一堆函数在 pandas 数据帧上运行并创建新列,然后应将其插入到 schools 或 students 表中(取决于我正在构建的内容)。一个典型的函数按顺序执行:
- 从两个 SQL 表中查询列
- 使用
groupby、自定义函数的apply、rolling_mean等pandas函数(其中许多在SQL上不可用,或者难以编写)来构造一个新列。返回类型为pd.Series或np.array - 将新列添加到适当的数据框(
schools或students)
这些函数是在我有一个适合内存的小型数据库时编写的,因此它们是纯 pandas。
这是一个伪代码示例:
def example_f(satisfaction, mean_scores)
"""Silly function that divides mean satisfaction per school by mean score"""
#here goes the pandas functions I already wrote
mean_satisfaction = mean(satisfaction)
return mean_satisfaction/mean_scores
satisf_div_score = example_f(satisfaction, mean_scores)
# Here push satisf_div_score to `schools` table
因为我的数据集非常大,我无法在内存中调用这些函数。想象一下,学校位于不同的地区。原来我只有一个区,所以我知道这些功能可以分别处理来自每个区的数据。
我认为可行的工作流程是:
- 查询小区
i相关数据 - 将函数应用于
i区的数据并生成新列作为 np.array 或 pd.Series - 在适当的表格中插入此列(将填充该列中
i区的数据 - 从
i= 1 到K的地区重复
虽然我的数据集在 SQLite 中(我希望它保持这种状态!)如果好处很大,我愿意将它迁移到其他东西。
我知道有不同的合理答案,但很高兴听到一些对你有用且简单的东西。谢谢!
【问题讨论】:
-
我有点古玩。你的桌子有多大?通常 pandas 可以在崩溃之前处理许多(数百万)条目。您提到使用
apply,这通常对性能不利,尽管有时是必要的。如果您真的内存不足,您的代码可能没有得到优化。寻找包含中间结果的变量,并通过尽快将它们分配给最终列来摆脱它们。否则,您建议的工作流程听起来很合理,如果这是您可以对其进行切片的最低级别。 -
如果您不想更改所选工具,您可以将数据集拆分为多个部分,例如按地区和/或学校编号。因此,您将获得小块数据的所有导数值均值、平均值等,这些数据可以很好地存储在内存中,并且可以快速计算。然后在
for s_id in schools: data=get_data_for_school(s_id); calc(data); write_to_sql(s_id, data)这样的伪循环中 -
另外,如果您的日期真的很大,我想考虑使用其他一些数据库:例如 PostgreSQL。它适用于不适合内存的大量数据,并且有一个特殊的window functions 来执行滚动平均值、位置等的计算。也许它可以在没有熊猫的情况下解决您的所有任务。随时提问。
-
@EugeneLisitsky:如果你想扩展你的想法(尽可能详细),那么我可以给你赏金。我提出了一个示例数据,以使该过程更容易。我认为更详细的答案也会使其他人受益!
-
@AskeDoerge :如果您有兴趣,同样适用。
标签: python sql database sqlite pandas