印度美食分析与相似性研究

一、项目背景

        印度是一个多民族、多文化的国家,拥有丰富多样的美食传统,其美食文化吸 引着大量的游客。印度各地区的菜肴风味和烹饪方式差异明显,了解这些差异对于 探索印度美食的奥秘至关重要。通过研究分析印度美食,帮助游客更好地理解不同 地区的菜肴特色,为他们提供更丰富的旅游体验。

二、业务需求

1、分析印度美食的特色。

2、找出印度美食的共同点。

三、项目实现

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

1、清洗数据

# 导入数据
ifood = pd.read_excel('indian_food1.xlsx')
ifood.head()

# 数据基本情况
ifood.info()

# 替换值
# 文件说明:值为-1都是NaN值
ifood = ifood.replace(-1,float('nan'))
ifood = ifood.replace('-1',float('nan'))
ifood.isna().sum()

 1.1、对prep_time 和 cook_time 列填充缺失值

# 填充缺失值
# 根据菜肴类型分类后,对prep_time 和 cook_time 使用众数填充

ls = ['prep_time', 'cook_time']
for i in ls:
    mode_per_group = ifood.groupby('course')[i].apply(lambda x: x.mode().iloc[0] if not x.mode().empty else None)
    ifood[i] = ifood.apply(lambda row: mode_per_group[row['course']] if pd.isna(row[i]) else row[i], axis=1)
ifood.isna().sum()

1.2、 对 state 列填充缺失值

1.2.1、进行编码和划分数据集
# 填充 state 列缺失值
from sklearn.preprocessing import LabelEncoder

# 暂时用‘A’填充state 列的缺失值
ifood['state'].fillna('A',inplace=True)

# 对已知''state' 列标签的diet','flavor_profile','course'列进行独热编码
dfcs = ifood[['diet','flavor_profile','course','state']]
dfcs_gd = pd.get_dummies(dfcs,columns=['diet','flavor_profile','course'])

# 对 'state' 列进行标签编码
le = LabelEncoder()
dfcs_gd['state'] = le.fit_transform(dfcs_gd['state'])

# 训练集既为‘state’列不为缺失值那部分
dfcs_gd_train =dfcs_gd[dfcs_gd['state']!=0] 
dfcs_gd_train.head()

# 预测集既‘state’列为缺失值那部分
dfcs_gd_pred =dfcs_gd[dfcs_gd['state']==0] 
dfcs_gd_pred.head()

from sklearn.model_selection import train_test_split

X = dfcs_gd_train.iloc[:,1:]
y = dfcs_gd_train.iloc[:,0]

# 将数据集分为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
 1.2.2、预测模型选择
# 决策树预测

from sklearn.metrics import accuracy_score, f1_score, classification_report
from sklearn.tree import DecisionTreeClassifier


# 创建决策树分类器
clf = DecisionTreeClassifier()

# 在训练集上训练决策树模型
clf.fit(X_train, y_train)

# 在测试集上进行预测
y_pred = clf.predict(X_test)

# 计算分类准确度
accuracy = accuracy_score(y_test, y_pred)
print(f"准确度: {accuracy}")

# 计算 F1 分数
f1 = f1_score(y_test, y_pred, average='weighted')
print(f"F1分数: {f1}")


from sklearn.metrics import accuracy_score, f1_score, classification_report
from sklearn.ensemble import RandomForestClassifier

# 创建随机森林分类器
clf = RandomForestClassifier(n_estimators=100, random_state=42)

# 在训练集上训练随机森林模型
clf.fit(X_train, y_train)

# 在测试集上进行预测
y_pred = clf.predict(X_test)

# 计算分类准确度
accuracy = accuracy_score(y_test, y_pred)
print(f"准确度: {accuracy}")

# 计算 F1 分数
f1 = f1_score(y_test, y_pred, average='weighted')
print(f"F1分数: {f1}")


from sklearn.metrics import accuracy_score, f1_score, classification_report
from sklearn.neighbors import KNeighborsClassifier

# 创建 KNN 分类器,设置 k 值
k = 3
clf = KNeighborsClassifier(n_neighbors=k)

# 在训练集上训练 KNN 模型
clf.fit(X_train, y_train)

# 在测试集上进行预测
y_pred = clf.predict(X_test)

# 计算分类准确度
accuracy = accuracy_score(y_test, y_pred)
print(f"准确度: {accuracy}")

# 计算 F1 分数
f1 = f1_score(y_test, y_pred, average='weighted')
print(f"F1分数: {f1}")


from sklearn.metrics import accuracy_score, f1_score, classification_report
from sklearn.naive_bayes import MultinomialNB

# 创建多项式朴素贝叶斯分类器
clf = MultinomialNB()

# 在训练集上训练朴素贝叶斯模型
clf.fit(X_train, y_train)

# 在测试集上进行预测
y_pred = clf.predict(X_test)

# 计算分类准确度
accuracy = accuracy_score(y_test, y_pred)
print(f"准确度: {accuracy}")

# 计算 F1 分数
f1 = f1_score(y_test, y_pred, average='weighted')
print(f"F1分数: {f1}")


from sklearn.metrics import accuracy_score, f1_score, classification_report
from sklearn.naive_bayes import GaussianNB

# 创建高斯朴素贝叶斯分类器
clf = GaussianNB()

# 在训练集上训练朴素贝叶斯模型
clf.fit(X_train, y_train)

# 在测试集上进行预测
y_pred = clf.predict(X_test)

# 计算分类准确度
accuracy = accuracy_score(y_test, y_pred)
print(f"准确度: {accuracy}")

# 计算 F1 分数
f1 = f1_score(y_test, y_pred, average='weighted')
print(f"F1分数: {f1}")
 1.2.3、使用模型预测state’列为缺失值那部分
# 经过比较众多个模型的准确度和F1 分数,最终决定使用随机森林模型预测‘state’列为缺失值那部分

from sklearn.metrics import accuracy_score, f1_score, classification_report
from sklearn.ensemble import RandomForestClassifier

# 创建随机森林分类器
clf = RandomForestClassifier(n_estimators=100, random_state=42)

# 在训练集上训练随机森林模型
clf.fit(X_train, y_train)

# 预测‘state’列为缺失值那部分
y_pred = clf.predict(dfcs_gd_pred.iloc[:,1:])
y_pred
 1.2.4、将预测结果填入原数据表
# 将预测得到新标签加入到dfcs_gd_pred
dfcs_gd_pred['label'] = y_pred

unique_states = ifood['state'].unique()  # 获取唯一值数组
unique_states_sorted = sorted(unique_states, reverse=False)  # 对唯一值数组进行降序排序

# 生成字典
result_dict = {}
for index, value in enumerate(unique_states_sorted):
    result_dict[index] = value

print(result_dict)

# 替换新值
dfcs_gd_pred['state'] = dfcs_gd_pred['label'].map(result_dict).fillna(dfcs_gd_pred['state'])


print('填充前:',ifood['state'].unique())

for row_index in ifood.index:
    if row_index in dfcs_gd_pred.index:
        ifood.loc[ifood.index == row_index,'state'] = dfcs_gd_pred.loc[dfcs_gd_pred.index == row_index,'state'].values[0]

print('填充后:',ifood['state'].unique())       

 1.3、填充region缺失值

sr = ifood[ifood['region'].notna()][['state','region']].drop_duplicates()

# 使用 .to_dict() 创建字典
sr_dict = sr.set_index('state')['region'].to_dict()
sr_dict

ifood['region'] = ifood['state'].map(sr_dict).fillna(ifood['region'])

1.4、 检查是否还有缺失值

ifood.isna().sum()

 1.5、异常值处理

# 根据course列分类
ifood.groupby('course')['prep_time','cook_time'].describe()

time = ['prep_time','cook_time']
course = ['dessert','main course','snack','starter']

for i in time:
    for j in course:
        a = ifood[i].loc[ifood['course']==j]
        mode = a.mode().values[0]
        q1 = a.quantile(0.25)
        q3 = a.quantile(0.75)
        iqr = q3 - q1
        lower_bound = q1 - 1.5*iqr
        upper_bound = q3 + 1.5*iqr
        ifood[i].loc[ifood['course']==j] = a.apply(lambda x:mode if x < lower_bound or x > upper_bound else x)
        

# 处理异常值后
ifood.groupby('course')['prep_time','cook_time'].describe()

2、数据可视化

df = pd.read_excel('indian_food1_clear.xlsx')
df.head()

2.1、饮食类型

diet = df['diet'].value_counts()

fig, axes = plt.subplots(1, 2, figsize=(10, 5))

color = ['lime','limegreen']

axes[0].pie(diet, labels=diet.index, colors=color ,autopct='%1.1f%%',  startangle=140)
axes[0].set_title(' 饮食类型占比')

diet_bar = axes[1].bar(diet.index, diet,color=color)
axes[1].bar_label(diet_bar,label_type='edge')
axes[1].set_title(' 饮食类型汇总')
axes[1].set_ylim((0,250))

plt.tight_layout()
plt.show()

印度美食的饮食类型绝大部分是素食,其中有226种素食,29种非素食

2.2、风味特征类型

flavor_profile = df['flavor_profile'].value_counts()

fig, axes = plt.subplots(1, 2, figsize=(10, 5))

color = ['cornflowerblue','royalblue','mediumblue','navy']

axes[0].pie(flavor_profile, labels=flavor_profile.index,colors=color , autopct='%1.1f%%',pctdistance=0.9)
axes[0].set_title(' 风味特征占比')

flavor_profile_bar = axes[1].bar(flavor_profile.index, flavor_profile,color=color)
axes[1].bar_label(flavor_profile_bar,label_type='edge')
axes[1].set_ylim((0,160))
axes[1].set_title(' 风味特征汇总')

plt.tight_layout()
plt.show()

印度美食的味道主要以辣和甜为主,200+印度美食中,有145种是辣的;102种是甜的;5种是苦的;3种是酸的

2.3、菜肴类型

course = df['course'].value_counts()

fig, axes = plt.subplots(1, 2, figsize=(10, 5))

color = ['aquamarine','turquoise','mediumturquoise','lightseagreen']

axes[0].pie(course, labels=course.index, colors=color, autopct='%1.1f%%',pctdistance=0.85)
axes[0].set_title('菜肴类型占比')

course_bar = axes[1].bar(course.index, course,color=color)
axes[1].bar_label(course_bar,label_type='edge')
axes[1].set_ylim((0,140))
axes[1].set_title(' 菜肴类型汇总')

plt.tight_layout()
plt.show()

在200+印度美食中,主菜占了50.6%,甜点占了33.3%,小吃占了15.3%,开胃菜只占了0.8%

2.4、原食材汇总

df1 = pd.read_excel('food.xlsx')
df2 = df1.sort_values(by='频数',ascending=False).head(30)

print('食材的种类数量总共是',len(df1['原料']))

plt.figure(figsize=(10,4))

x = df2['原料']
y = df2['频数']

df1_bar = plt.bar(x,y,color='deepskyblue')
plt.bar_label(df1_bar,label_type='edge')
plt.title('原食材汇总TOP30')
plt.ylim((0,60))
plt.xticks(x,rotation=90)
plt.show()

200+印度美食主要使用的食材有384种,用来做调味料的有糖、生姜、咖喱叶、酥油、青辣椒等;常用的食材有米粉、番茄、土豆、小麦粉、椰子、芝麻等。

2.5、准备时间&烹饪时间

cook = df['cook_time'].value_counts()

plt.figure(figsize=(10,4))

x = np.arange(len(cook))
y = cook

cook_bar = plt.bar(x,y,color='salmon')
plt.bar_label(cook_bar,label_type='edge')
plt.title('食材烹饪时间情况')
plt.xlabel('分钟')
plt.xticks(x,cook.index)
plt.show()

prep = df['prep_time'].value_counts()

plt.figure(figsize=(10,4))

x = np.arange(len(prep))
y = prep

prep_bar = plt.bar(x,y,color='palegreen')
plt.bar_label(prep_bar,label_type='edge')
plt.title('食材准备时间情况')
plt.xlabel('分钟')
plt.xticks(x,prep.index)
plt.show()

总体来看,每道美食的食材准备时间大约是10-20分钟;烹饪时间大约是20-40分钟

2.6、不同菜肴类型上菜速度

cook_time = pd.crosstab(index=df['cook_time'], columns=df['course'])

fig,axes = plt.subplots(2,2,figsize=(18,10))

x = np.arange(len(cook_time.index))
dessert = cook_time['dessert']
main_course = cook_time['main course']
snack = cook_time['snack']
starter = cook_time['starter']

title_fontsize=25

dessert_bar = axes[0,0].bar(x,dessert,label='dessert',color='gold')
axes[0,0].bar_label(dessert_bar,label_type='edge')
axes[0,0].set_title('dessert', fontsize=title_fontsize)
axes[0,0].set_xlabel('分钟')
axes[0,0].set_xticks(x)
axes[0,0].set_xticklabels(cook_time.index)

main_course_bar = axes[0,1].bar(x,main_course,label='main_course',color='khaki')
axes[0,1].bar_label(main_course_bar,label_type='edge')
axes[0,1].set_title('main_course', fontsize=title_fontsize)
axes[0,1].set_xlabel('分钟')
axes[0,1].set_xticks(x)
axes[0,1].set_xticklabels(cook_time.index)

snack_bar = axes[1,0].bar(x,snack,label='snack',color='goldenrod')
axes[1,0].bar_label(snack_bar,label_type='edge')
axes[1,0].set_title('snack', fontsize=title_fontsize)
axes[1,0].set_xlabel('分钟')
axes[1,0].set_xticks(x)
axes[1,0].set_xticklabels(cook_time.index)

starter_bar = axes[1,1].bar(x,starter,label='starter',color='darkkhaki')
axes[1,1].bar_label(starter_bar,label_type='edge')
axes[1,1].set_title('starter', fontsize=title_fontsize)
axes[1,1].set_xlabel('分钟')
axes[1,1].set_xticks(x)
axes[1,1].set_xticklabels(cook_time.index)

plt.tight_layout()
plt.show()

2.7饮食地域性差异

region_diet = pd.crosstab(index=df['region'], columns=df['diet'])
region_flavor_profile = pd.crosstab(index=df['region'], columns=df['flavor_profile'])

fig, axes = plt.subplots(2, 1, figsize=(10, 8))

width1 = 0.25
x1 = np.arange(len(region_diet.index))

width2 = 0.25
x2 = np.arange(len(region_flavor_profile.index))
group_num = 4
group_width = 1
bar_span = group_width / group_num
bar_width = bar_span - 0.1
baseline_x = x2 - (group_width - bar_span) / 2

non_vegetarian_bar = axes[0].bar(x1 - width1/2, region_diet['non vegetarian'], width1,color='brown', label='non vegetarian')
vegetarian_bar = axes[0].bar(x1 + width1/2, region_diet['vegetarian'], width1,color='lightcoral', label='vegetarian')
axes[0].bar_label(non_vegetarian_bar,label_type='edge')
axes[0].bar_label(vegetarian_bar,label_type='edge')
axes[0].set_xticks(x1)
axes[0].set_xticklabels(region_diet.index)
axes[0].legend()
axes[0].set_title('地区饮食差异')

bitter_bar = axes[1].bar(baseline_x + 0*bar_span, region_flavor_profile['bitter'], width2,color='thistle', label='bitter')
sour_bar = axes[1].bar(baseline_x + 1*bar_span, region_flavor_profile['sour'], width2,color='plum', label='sour')
spicy_bar = axes[1].bar(baseline_x + 2*bar_span, region_flavor_profile['spicy'], width2,color='violet', label='spicy')
sweet_bar = axes[1].bar(baseline_x + 3*bar_span, region_flavor_profile['sweet'], width2,color='fuchsia', label='sweet')
axes[1].bar_label(bitter_bar,label_type='edge')
axes[1].bar_label(sour_bar,label_type='edge')
axes[1].bar_label(spicy_bar,label_type='edge')
axes[1].bar_label(sweet_bar,label_type='edge')
axes[1].set_xticks(x2)
axes[1].set_xticklabels(region_flavor_profile.index)
axes[1].legend()
axes[1].set_title('地区口味特点差异')

plt.tight_layout()
plt.show()

每个地区都有素食,每个地区的美食味道都有辣的和甜的。其中South最为突出,素食美食是最多的,辣的美食和甜的美食也是最多的

Central和East的美食全是素食

每个地区的酸和苦的美食数量很少,甚至有的地区没有。

# 每个地区的城市数量
state_region_num = df[['state','region']].drop_duplicates()['region'].value_counts()

x = np.arange(len(state_region_num.index))

plt.subplots(figsize=(10, 6))

state_region_num_bar = plt.bar(x,state_region_num,color='blueviolet')
plt.bar_label(state_region_num_bar,label_type='edge')
plt.title('每个地区的城市数量')
plt.ylim((0,10))
plt.xticks(x,state_region_num.index)
plt.show()

# 每个城市的美食数量

region_state_food = df.groupby('region')['state'].value_counts().reset_index(name='frequency')

# 创建颜色映射和类别列表
color_mapping = {'Central': 'b', 'East': 'orange', 'North': 'r', 'North East': 'c', 'South': 'g','West':'y'}
categories = region_state_food['region'].unique()

# 绘制柱形图
fig, ax = plt.subplots(figsize=(16, 6))

for category in categories:
    subset = region_state_food[region_state_food['region'] == category]
    x = subset['state']
    y = subset['frequency']
    color = color_mapping.get(category, 'gray')  # 获取颜色映射,如果没有匹配则使用灰色
    a=ax.bar(x, y, color=color, label=category)
    ax.bar_label(a,label_type='edge')
plt.xlabel('state')
plt.title('每个城市的美食数量')
plt.xticks(region_state_food['state'],rotation=90)
# 添加图例
ax.legend(title='所属地区')

plt.show()

四、数据分析结果:

结论:

从饮食类型来看,这份美食菜单包括超过200道菜肴,绝大部分是素食,而只有极少数是荤食。

从风味特征来看,这些美食以辣味和甜味为主要特点,为人们提供了多种口味选择。

从菜肴类型来看,主食类菜肴数量最多,其次是甜点和小吃,为顾客提供了多种丰富的选择。

食材的烹饪时间通常在20-40分钟之间,而食材准备时间一般在10-20分钟左右。不同类型的菜肴可能需要不同的烹饪时间,但总体来说,烹饪时间大致相似,通常在20-40分钟内即可上菜。

从地域性差异来看,South(南印度)和West(西印度)地区的素食菜肴数量最为丰富。West地区以其辛辣和甜味的美食而闻名,像Gujarat(古吉拉特)、Punjab(旁遮普)、West Bengal(西孟加拉)、Maharashtra(马哈拉施特拉邦)、Assam(阿萨姆)等城市提供了众多美味佳肴。总的来看,每个地区都有一个城市在美食方面表现出色,呈现出多样化的口味和烹饪风格。

建议:

尝试素食美食:由于绝大部分菜肴是素食,建议游客尝试一些丰富多彩的素食菜品,以体验印度素食文化的独特魅力。

探索辣味和甜味:辣味和甜味是印度美食的主要特点,不妨品尝一些辛辣和甜味美食,但要注意个人的辣度偏好,有些印度美食可能非常辛辣。

多样化的选择:主食、甜点和小吃都有丰富的选择,建议游客尝试各类不同类型的菜肴,以充分体验印度的风味。

考虑等候时间:烹饪时间通常在20-40分钟之间,游客需要考虑等候时间,特别是在高峰时段,提前下单或者选择不太繁忙的时间用餐可能更好。

探索地域性美食:根据地域性差异,不妨探索不同地区的美食,例如在South和West地区品尝当地的素食和辣味佳肴,以及在城市如Gujarat、Punjab、West Bengal、Maharashtra、Assam尝试当地特色。

了解上菜速度:各种菜肴的上菜速度可能不同,一些美食可能会更快上桌,根据个人时间安排作出选择。

总之,印度的美食文化丰富多彩,游客可以尝试不同类型的菜肴,享受独特的口味和文化体验。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值