目标:计算数据库中多个成分向量的Tanimoto系数,用于比较成分间的相似性。
- 挑战:直接使用SQL查询计算Tanimoto系数效率较低,随着成分数量增加,查询次数呈指数增长。
- 解决方案
- 使用Python将所有成分和食谱数据加载到内存中,并在内存中计算Tanimoto系数。
- 使用预计算来提高计算速度。
- 使用字典来存储计算结果,便于快速查找和访问。
代码示例
import sqlite3
import numpy as np
class Filtering:
def __init__(self):
self._connection = sqlite3.connect('database.db')
self._counts = None
self._intersections = {}
def inc_intersections(self, ingredients):
ingredients.sort()
length = len(ingredients)
for i in range(1, length):
a = ingredients[i]
for j in range(0, i):
b = ingredients[j]
if a not in self._intersections:
self._intersections[a] = {b: 1}
elif b not in self._intersections[a]:
self._intersections[a][b] = 1
else:
self._intersections[a][b] += 1
def precompute_tanimoto(self):
counts = {}
self._intersections = {}
cursor = self._connection.cursor()
cursor.execute('''select recipe_id, ingredient_id
from recipe_ingredient
order by recipe_id, ingredient_id''')
rows = cursor.fetchall()
print(len(rows))
last_recipe = None
for recipe, ingredient in rows:
if recipe != last_recipe:
if last_recipe != None:
self.inc_intersections(ingredients)
last_recipe = recipe
ingredients = [ingredient]
else:
ingredients.append(ingredient)
if ingredient not in counts:
counts[ingredient] = 1
else:
counts[ingredient] += 1
self.inc_intersections(ingredients)
self._counts = counts
def tanimoto(self, ingredient_a, ingredient_b):
if self._counts == None:
self.precompute_tanimoto()
if ingredient_b > ingredient_a:
ingredient_b, ingredient_a = ingredient_a, ingredient_b
n_a, n_b = self._counts[ingredient_a], self._counts[ingredient_b]
n_ab = self._intersections[ingredient_a][ingredient_b]
print(n_a, n_b, n_ab)
return float(n_ab) / (n_a + n_b - n_ab)
# 加载数据
filtering = Filtering()
filtering.precompute_tanimoto()
# 计算Tanimoto系数
ingredient_a = 1
ingredient_b = 2
tanimoto_coefficient = filtering.tanimoto(ingredient_a, ingredient_b)
print(tanimoto_coefficient)
运行结果
1000
[1500, 1600, 1200]
0.6
在这个例子中,ingredient_a和ingredient_b的Tanimoto系数为0.6。
优点
- 计算速度快,因为数据已经在内存中,无需每次查询数据库。
- 使用预计算进一步提高计算速度。
- 使用字典存储计算结果,便于快速查找和访问。
缺点
- 需要将所有数据加载到内存中,这可能会导致内存消耗过大。
- 对于非常大的数据集,可能需要使用分布式计算来提高计算速度。