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

Python餐厅推荐系统向量维度不匹配ValueError问题求助

餐厅推荐系统维度不匹配ValueError问题排查与解决

我用Python开发了一款结合用户偏好(菜系、价位)和余弦相似度的餐厅推荐系统,当前碰到ValueError: User preference vector and restaurant feature vectors must have the same number of dimensions错误,两种场景都会触发:

  • 场景1:餐厅数据用one-hot编码处理菜系,用户选择“所有菜系”(生成全1的one-hot向量)时报错
  • 场景2:用户选择特定菜系(生成仅单一特征为1的one-hot向量)时同样报错

我怀疑是用户偏好向量与餐厅数据中的菜系表示不匹配(比如单菜系与多菜系列表的差异),以下是相关代码与报错栈信息:


一、用户偏好函数

# 两个重载的get_user_preferences函数
def get_user_preferences(cuisine=None, price_range=None):
    # 初始化空的偏好向量
    user_pref = [0] * len(encoder.get_feature_names_out())
    # 设置菜系偏好(one-hot编码)
    if cuisine:
        cuisine_index = encoder.get_feature_names_out().tolist().index(cuisine)
        user_pref[cuisine_index] = 1
    # 设置价位
    if price_range:
        user_pref.append(price_range)  # 假设价位为数值型
    return user_pref

def get_user_preferences(cuisine=None, price_range=None):
    """
    返回:包含one-hot编码菜系与价位的用户偏好向量列表。
    """
    # 初始化对所有菜系偏好均等的空向量
    num_cuisines = len(encoder.get_feature_names_out())
    user_pref = [1 / num_cuisines] * num_cuisines

    # 设置菜系偏好(one-hot编码)
    if cuisine:
        cuisine_index = encoder.get_feature_names_out().tolist().index(cuisine)
        user_pref[cuisine_index] = 1

    # 设置价位
    if price_range:
        user_pref.append(price_range)  # 假设价位为数值型

    return user_pref

二、余弦相似度与用户输入函数

def cosine_similarity(user_pref, restaurant_vec):
    # 从用户偏好与餐厅向量中提取菜系向量
    user_pref_cuisine = user_pref[:-1] if len(user_pref) > 1 else user_pref  # 若有则排除价位
    restaurant_vec_cuisine = restaurant_vec[:-1] if len(restaurant_vec) > 1 else restaurant_vec

    # 检查用户菜系向量与餐厅菜系向量长度是否一致
    if len(user_pref_cuisine) != len(restaurant_vec_cuisine):
        raise ValueError("User preference cuisine vector and restaurant cuisine vector must have the same number of dimensions.")

    # 计算余弦相似度
    return np.dot(user_pref_cuisine, restaurant_vec_cuisine) / (np.linalg.norm(user_pref_cuisine) * np.linalg.norm(restaurant_vec_cuisine))

def get_user_preferences_from_user():
    """
    该函数提示用户选择偏好的菜系与价位。
    返回:包含one-hot编码菜系与价位的用户偏好向量列表。
    """
    # 获取用户菜系输入
    available_cuisines = list(df['Cuisines'].unique())  # 假设唯一菜系存储在某列中
    while True:
        cuisine = input("Enter your preferred cuisine (or 'all' for any): ").lower().strip()
        if cuisine in available_cuisines or cuisine == 'all':
            break
        else:
            print(f"Invalid cuisine. Available options are: {', '.join(available_cuisines)}")

    # 获取用户价位输入
    price_ranges = {
        "1": "Cheap",
        "2": "Moderate",
        "3": "Fine Dining"
    }
    while True:
        price_range = input("Enter your preferred price range (1 - Cheap, 2 - Moderate, 3 - Fine Dining): ")
        if price_range in price_ranges:
            break
        else:
            print(f"Invalid price range. Please enter 1, 2, or 3.")

    # 编码菜系(非“所有”时)
    if cuisine != 'all':
        cuisine_index = encoder.get_feature_names_out().tolist().index(cuisine)
        user_pref = [0] * len(encoder.get_feature_names_out())
        user_pref[cuisine_index] = 1
    else:
        user_pref = [1] * len(encoder.get_feature_names_out())  # 对所有菜系进行one-hot编码

    # 若指定则添加价位
    if price_range:
        user_pref.append(int(price_range))

    # 确保用户偏好向量与餐厅特征向量的特征数量一致
    if len(user_pref) != len(df.drop(columns=['Restaurant Name']).values[0]):
        raise ValueError("User preference vector and restaurant feature vectors must have the same number of dimensions.")

    return user_pref

三、餐厅推荐函数

def recommend_restaurants(user_pref, df=df, top_n=5):
    """
    基于用户偏好与相似度分数推荐餐厅。
    参数:
    user_pref (list): 用户偏好向量。
    df (pandas.DataFrame, 可选): 预处理后的餐厅数据,默认值为df。
    top_n (int, 可选): 返回的顶级推荐数量,默认值为5。
    返回:
    pandas.DataFrame: 包含详细信息的前N个推荐餐厅。
    """
    # 构建包含编码菜系的餐厅特征向量
    restaurant_feature_vectors = df.drop(columns=['Restaurant Name']).values

    # 检查用户偏好向量与餐厅特征向量的维度是否一致
    if len(user_pref) != len(restaurant_feature_vectors[0]):
        raise ValueError("User preference vector and restaurant feature vectors must have the same number of dimensions.")

    # 计算每个餐厅的相似度
    similarities = np.array([cosine_similarity(user_pref, vec) for vec in restaurant_feature_vectors])

    # 按相似度降序排序
    df_sorted = df.assign(similarity=similarities).sort_values(by='similarity', ascending=False)

    # 返回前N个结果
    return df_sorted.head(top_n).drop('similarity', axis=1)

调用代码与报错信息

调用代码

# 获取用户偏好
user_pref = get_user_preferences_from_user()

# 生成推荐
recommendations = recommend_restaurants(user_pref, df=df)

print("Top Restaurant Recommendations:")
print(recommendations)

用户输入

Enter your preferred cuisine (or 'all' for any): all
Enter your preferred price range (1 - Cheap, 2 - Moderate, 3 - Fine Dining): 4
Invalid price range. Please enter 1, 2, or 3.
Enter your preferred price range (1 - Cheap, 2 - Moderate, 3 - Fine Dining): 1

报错栈

ValueError                                Traceback (most recent call last)
 in <cell line: 2>()
1 # 假设存在获取用户菜系与价位输入的函数
----> 2 user_pref = get_user_preferences_from_user()  # 替换为你的函数
3
4 # 调用推荐函数并传入数据与用户偏好
5 recommendations = recommend_restaurants(user_pref, df=df)  # 使用你的df数据

 in get_user_preferences_from_user()
42     # 确保用户偏好向量与餐厅特征向量的特征数量一致
43     if len(user_pref) != len(df.drop(columns=['Restaurant Name']).values[0]):
---> 44         raise ValueError("User preference vector and restaurant feature vectors must have the same number of dimensions.")
45
46     return user_pref

ValueError: User preference vector and restaurant feature vectors must have the same number of dimensions.

问题排查与解决方案

核心原因

  1. 向量维度对齐错误:用户偏好向量是先构建one-hot菜系向量,再追加价位特征;但餐厅数据的特征向量中,价位是作为固定列存在的,不是追加项。若餐厅数据特征列数为菜系one-hot列数 + 1(价位),但用户向量构建逻辑导致长度不匹配,就会触发错误。
  2. 菜系编码范围不匹配:encoder.get_feature_names_out()生成的菜系列,与df中实际的one-hot编码菜系列数不一致(比如餐厅存在多菜系标记,one-hot后列数更多)。

修复步骤

步骤1:确认特征列结构

先打印餐厅数据的特征列信息,验证维度是否匹配:

# 打印餐厅特征列与encoder生成的菜系列
print("餐厅特征列:", df.drop(columns=['Restaurant Name']).columns.tolist())
print("Encoder生成的菜系列:", encoder.get_feature_names_out().tolist())
print("餐厅特征列数:", len(df.drop(columns=['Restaurant Name']).columns))
print("Encoder菜系列数:", len(encoder.get_feature_names_out()))

确保餐厅特征列数 = 菜系one-hot列数 + 价位列数(1列)。

步骤2:修正用户偏好向量构建逻辑

不要直接追加价位,而是将价位放在与餐厅数据对应的列位置:

def get_user_preferences_from_user():
    # ... 保留前面的用户输入逻辑 ...

    # 初始化偏好向量,长度与餐厅特征列一致
    feature_cols = df.drop(columns=['Restaurant Name']).columns.tolist()
    user_pref = [0] * len(feature_cols)

    # 填充菜系部分
    cuisine_cols = encoder.get_feature_names_out().tolist()
    if cuisine != 'all':
        # 找到目标菜系在特征列中的索引并赋值
        for idx, col in enumerate(feature_cols):
            if col == cuisine:
                user_pref[idx] = 1
                break
    else:
        # 所有菜系列赋值为1
        for idx, col in enumerate(feature_cols):
            if col in cuisine_cols:
                user_pref[idx] = 1

    # 填充价位部分(假设餐厅数据中价位列名为Price_Range)
    price_col_idx = feature_cols.index('Price_Range') if 'Price_Range' in feature_cols else None
    if price_range and price_col_idx is not None:
        user_pref[price_col_idx] = int(price_range)

    return user_pref

步骤3:修正余弦相似度计算逻辑

基于菜系列的实际索引提取向量,而非简单截取[:-1]:

def cosine_similarity(user_pref, restaurant_vec):
    feature_cols = df.drop(columns=['Restaurant Name']).columns.tolist()
    cuisine_cols = encoder.get_feature_names_out().tolist()
    # 获取所有菜系列的索引
    cuisine_indices = [feature_cols.index(col) for col in cuisine_cols]

    # 提取菜系向量
    user_pref_cuisine = [user_pref[i] for i in cuisine_indices]
    restaurant_vec_cuisine = [restaurant_vec[i] for i in cuisine_indices]

    # 计算余弦相似度
    return np.dot(user_pref_cuisine, restaurant_vec_cuisine) / (np.linalg.norm(user_pref_cuisine) * np.linalg.norm(restaurant_vec_cuisine))

步骤4:适配多菜系场景

如果餐厅存在多菜系标记(如“中餐, 川菜”),one-hot编码后对应列都会是1。此时用户选“所有菜系”时,所有菜系列设为1,可正常匹配这类餐厅的特征。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 21:15:53