矢量图保存方法

Creato il: 27 gennaio 2025

Risposto usando O1 da Chat01

Domanda

import os
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import math
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error

##########################################################################

1) 第一段代码: 奥运奖牌预测 & 进步退步分析

##########################################################################

读取 athletes & medal_counts

athletes = pd.read_csv('summerOly_athletes.csv', encoding='ISO-8859-1')
medal_counts = pd.read_csv('summerOly_medal_counts.csv', encoding='ISO-8859-1')

Merge & Preprocess

medal_summary = medal_counts.groupby(['Year','NOC'], as_index=False).agg({
'Gold':'sum','Silver':'sum','Bronze':'sum','Total':'sum'
})
athlete_summary = athletes.groupby(['Year','NOC'], as_index=False).size().rename(columns={'size':'Athletes'})
data = pd.merge(medal_summary, athlete_summary, on=['Year','NOC'], how='left').fillna(0)

Rolling historical features

data.sort_values(['NOC','Year'], inplace=True)
data['Past_Gold_Avg'] = data.groupby('NOC')['Gold'].transform(
lambda x: x.shift().rolling(window=3, min_periods=1).mean())
data['Past_Total_Avg'] = data.groupby('NOC')['Total'].transform(
lambda x: x.shift().rolling(window=3, min_periods=1).mean())
data['Past_Gold_Sum'] = data.groupby('NOC')['Gold'].transform(
lambda x: x.shift().rolling(window=3, min_periods=1).sum())
data['Past_Total_Sum'] = data.groupby('NOC')['Total'].transform(
lambda x: x.shift().rolling(window=3, min_periods=1).sum())
data[['Past_Gold_Avg','Past_Total_Avg','Past_Gold_Sum','Past_Total_Sum']] =
data[['Past_Gold_Avg','Past_Total_Avg','Past_Gold_Sum','Past_Total_Sum']].fillna(0)

features = ['Past_Gold_Avg','Past_Total_Avg','Past_Gold_Sum','Past_Total_Sum']
target_gold = 'Gold'
target_total = 'Total'

def build_model(df, feats, target):
X = df[feats]
y = df[target]
X_train, X_test, y_train, y_test = train_test_split(X, y,
test_size=0.2,
random_state=42)
model = LinearRegression()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
mse = mean_squared_error(y_test, y_pred)
print(f"Model for {target}: MSE = {mse}")
return model

model_gold = build_model(data, features, target_gold)
model_total = build_model(data, features, target_total)

Predict for 2028

unique_nocs = data['NOC'].unique()
df_2024 = data[data['Year']==2024].copy()
group_2024 = df_2024.groupby('NOC', as_index=False)[features].mean()

future_data = pd.DataFrame({'NOC': unique_nocs})
future_data = pd.merge(future_data, group_2024, on='NOC', how='left').fillna(0)

pred_gold = model_gold.predict(future_data[features])
pred_total = model_total.predict(future_data[features])

pred_gold = np.clip(pred_gold, a_min=0, a_max=None)
pred_total = np.clip(pred_total, a_min=0, a_max=None)

future_data['Predicted_Gold'] = pd.Series(pred_gold).round().astype(int)
future_data['Predicted_Total'] = pd.Series(pred_total).round().astype(int)

gold_res = model_gold.predict(data[features]) - data[target_gold]
total_res = model_total.predict(data[features]) - data[target_total]
gold_std = gold_res.std()
total_std = total_res.std()

future_data['Gold_Lower'] = (future_data['Predicted_Gold'] - 2gold_std).clip(lower=0).round().astype(int)
future_data['Gold_Upper'] = (future_data['Predicted_Gold'] + 2
gold_std).clip(lower=0).round().astype(int)
future_data['Total_Lower'] = (future_data['Predicted_Total'] - 2total_std).clip(lower=0).round().astype(int)
future_data['Total_Upper'] = (future_data['Predicted_Total'] + 2
total_std).clip(lower=0).round().astype(int)

future_data.sort_values(by='Predicted_Total', ascending=False, inplace=True)
print("Predicted Medal Table for 2028 Los Angeles Olympics:")
print(
future_data[['NOC','Predicted_Gold','Gold_Lower','Gold_Upper',
'Predicted_Total','Total_Lower','Total_Upper']]
)

future_data.to_csv('Predicted_Medal_Table_2028.csv', index=False)
print("Results saved to 'Predicted_Medal_Table_2028.csv'")

plt.figure(figsize=(12, 8))
sns.barplot(x='NOC', y='Predicted_Total', data=future_data.head(10), palette='viridis')
plt.title('Predicted Total Medals in 2028 (Vertical Bars)')
plt.xlabel('Country (NOC)')
plt.ylabel('Predicted Total Medals')
plt.xticks(rotation=45, ha='right')
plt.tight_layout()
plt.show()

future_data['Gold_History'] = data.groupby('NOC')['Past_Gold_Avg'].mean().reindex(unique_nocs).fillna(0).values
future_data['Total_History'] = data.groupby('NOC')['Past_Total_Avg'].mean().reindex(unique_nocs).fillna(0).values

future_data['Gold_Progress'] = future_data['Predicted_Gold'] - future_data['Gold_History']
future_data['Total_Progress'] = future_data['Predicted_Total'] - future_data['Total_History']
future_data['Gold_Trend'] = np.where(future_data['Gold_Progress']>0, 'Progress','Decline')
future_data['Total_Trend'] = np.where(future_data['Total_Progress']>0, 'Progress','Decline')

progress_gold = future_data[['NOC','Predicted_Gold','Gold_Progress','Gold_Trend']]
.sort_values('Gold_Progress', ascending=False)
decline_gold = future_data[['NOC','Predicted_Gold','Gold_Progress','Gold_Trend']]
.sort_values('Gold_Progress', ascending=True)
progress_total = future_data[['NOC','Predicted_Total','Total_Progress','Total_Trend']]
.sort_values('Total_Progress', ascending=False)
decline_total = future_data[['NOC','Predicted_Total','Total_Progress','Total_Trend']]
.sort_values('Total_Progress', ascending=True)

print("\nCountries Most Likely to Improve in Gold:")
print(progress_gold.head(10))
print("\nCountries Most Likely to Decline in Gold:")
print(decline_gold.head(10))
print("\nCountries Most Likely to Improve in Total Medals:")
print(progress_total.head(10))
print("\nCountries Most Likely to Decline in Total Medals:")
print(decline_total.head(10))

plt.figure(figsize=(12, 8))
sns.barplot(x='NOC', y='Gold_Progress', data=progress_gold.head(10), palette='Blues')
plt.title('Top 10 Countries Likely to Improve in Gold (Vertical Bars)')
plt.xlabel('Country (NOC)')
plt.ylabel('Gold Medal Progress')
plt.xticks(rotation=45, ha='right')
plt.tight_layout()
plt.show()

plt.figure(figsize=(12, 8))
sns.barplot(x='NOC', y='Gold_Progress', data=decline_gold.head(10), palette='Reds')
plt.title('Top 10 Countries Likely to Decline in Gold (Vertical Bars)')
plt.xlabel('Country (NOC)')
plt.ylabel('Gold Medal Decline')
plt.xticks(rotation=45, ha='right')
plt.tight_layout()
plt.show()

plt.figure(figsize=(12, 8))
sns.barplot(x='NOC', y='Total_Progress', data=progress_total.head(10), palette='Blues')
plt.title('Top 10 Countries Likely to Improve in Total Medals (Vertical Bars)')
plt.xlabel('Country (NOC)')
plt.ylabel('Total Medal Progress')
plt.xticks(rotation=45, ha='right')
plt.tight_layout()
plt.show()

plt.figure(figsize=(12, 8))
sns.barplot(x='NOC', y='Total_Progress', data=decline_total.head(10), palette='Reds')
plt.title('Top 10 Countries Likely to Decline in Total Medals (Vertical Bars)')
plt.xlabel('Country (NOC)')
plt.ylabel('Total Medal Decline')
plt.xticks(rotation=45, ha='right')
plt.tight_layout()
plt.show()

future_data_gold_sorted = future_data.sort_values('Predicted_Gold', ascending=False)
top10_gold = future_data_gold_sorted.head(10)
others_gold = future_data_gold_sorted.iloc[10:]['Predicted_Gold'].sum()
labels = list(top10_gold['NOC'].values) + ['Others']
values = list(top10_gold['Predicted_Gold'].values) + [others_gold]

top_colors = sns.color_palette('Set2', n_colors=len(top10_gold))
others_color = [(0.5,0.5,0.5)]
colors = top_colors + others_color
explode = [0]*(len(top10_gold)) + [0.1]

plt.figure(figsize=(8,8))
plt.pie(
values,
labels=labels,
colors=colors,
explode=explode,
autopct='%1.1f%%',
startangle=160,
wedgeprops={'alpha':0.9},
labeldistance=1.12,
pctdistance=0.75
)
plt.title("Predicted Gold Share: Top 10 vs. Others (2D Pie)")
plt.axis('equal')
plt.tight_layout()
plt.show()

##########################################################################

2) 第二段代码: “断轴”示例 (保留原逻辑 + 输出)

##########################################################################

countries = ["Yugoslavia","Turkey","Croatia","Canada","Costa Rica",
"Latvia","Indonesia","Nigeria","Kyrgyzstan","Finland"]
values = [0.67,0.65,0.52,0.50,0.49,0.48,0.48,0.47,0.47,0.46]
gold_prob_mod = pd.Series(data=values, index=countries)

x_labels = gold_prob_mod.index
x_vals = np.arange(len(x_labels))

fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True, figsize=(8,6))
fig.subplots_adjust(hspace=0.05)

ax1.bar(x_vals, gold_prob_mod, color='skyblue', edgecolor='black')
ax1.set_ylim(0.45, 0.7)
ax1.spines['bottom'].set_visible(False)
ax1.tick_params(labelbottom=False)

ax2.bar(x_vals, gold_prob_mod, color='skyblue', edgecolor='black')
ax2.set_ylim(0, 0.4)

d = .01
kwargs = dict(transform=ax1.transAxes, color='k', clip_on=False)
ax1.plot((-d, +d), (-d, +d), **kwargs)
ax1.plot((1 - d, 1 + d), (-d, +d), **kwargs)

kwargs = dict(transform=ax2.transAxes, color='k', clip_on=False)
ax2.plot((-d, +d), (1 - d, 1 + d), **kwargs)
ax2.plot((1 - d, 1 + d), (1 - d, 1 + d), **kwargs)

ax2.set_xticks(x_vals)
ax2.set_xticklabels(x_labels, rotation=45, ha='right')
ax2.set_xlabel("Country (NOC)")
ax2.set_ylabel("Probability of 'trend>0'")
ax1.set_title("Top 10 Zero-Gold Countries (Broken Y-Axis)")

plt.tight_layout()
plt.show()

##########################################################################

========== PART A: 生成 yearly_summary 并画两张图 ==========

##########################################################################

base_dir = r"D:\浏览器下载\pycharm\olympic\my_olympic_project.venv"
programs_file_path = os.path.join(base_dir, 'summerOly_programs.csv')
medal_counts_file_path = os.path.join(base_dir, 'summerOly_medal_counts.csv')
output_excel = os.path.join(base_dir, 'yearly_summary.xlsx')

programs_df = pd.read_csv(programs_file_path, encoding='ISO-8859-1')
medal_counts_df = pd.read_csv(medal_counts_file_path, encoding='ISO-8859-1')

programs_df_cleaned = programs_df.loc[:, ~programs_df.columns.str.contains("Code|Sport|Discipline|Sports Governing Body")]
programs_df_cleaned = programs_df_cleaned.rename(columns=lambda x: x.strip().replace('*','') if isinstance(x, str) else x)
programs_df_cleaned = programs_df_cleaned.apply(pd.to_numeric, errors='coerce')

programs_melted_cleaned = programs_df_cleaned.melt(var_name='Year', value_name='Number_of_Events')
programs_melted_cleaned['Year'] = pd.to_numeric(programs_melted_cleaned['Year'], errors='coerce', downcast='integer')

medal_counts_per_year = medal_counts_df.groupby(['Year','NOC'])['Gold'].sum().reset_index()
merged_data_cleaned = pd.merge(medal_counts_per_year, programs_melted_cleaned, how='left', on='Year')

yearly_summary = merged_data_cleaned.groupby('Year').agg({
'Number_of_Events':'sum',
'Gold':'sum'
}).reset_index()

yearly_summary['Gold_to_Event_Ratio'] = yearly_summary['Gold'] / yearly_summary['Number_of_Events']
yearly_summary['Gold_to_Event_Ratio'] = yearly_summary['Gold_to_Event_Ratio'].fillna(0)

yearly_summary.to_excel(output_excel, index=False)
print(f"yearly_summary 已保存至: {output_excel}")
print(yearly_summary.head(10))

plt.figure(figsize=(12, 6))
plt.plot(yearly_summary['Year'], yearly_summary['Gold_to_Event_Ratio'], marker='o', color='purple')
plt.title("Gold to Event Ratio per Year (1896-2024)", fontsize=14)
plt.xlabel("Year", fontsize=12)
plt.ylabel("Gold to Event Ratio", fontsize=12)
plt.tight_layout()
plt.show()

plt.figure(figsize=(12, 6))
plt.plot(yearly_summary['Year'], yearly_summary['Number_of_Events'], label="Number of Events", marker='o', color='b')
plt.plot(yearly_summary['Year'], yearly_summary['Gold'], label="Gold Medals", marker='o', color='g')
plt.title("Relationship between Number of Events and Gold Medal Counts (1896-2024)", fontsize=14)
plt.xlabel("Year", fontsize=12)
plt.ylabel("Count", fontsize=12)
plt.legend(title="Legend")
plt.tight_layout()
plt.show()

##########################################################################

========== PART B: 生成“平滑”模拟数据并画折线图 ==========

##########################################################################

N = 20
x_start = 10
x_vals = np.arange(x_start, x_start + N)
gold_list = []

rng = np.random.default_rng(2028)
for x in x_vals:
base = 2*x + 10
wave = math.sin(x/2)*3
y = round(base + wave)
gold_list.append(y)

df_line = pd.DataFrame({
'Number_of_Events': x_vals,
'Gold': gold_list
})

df_line.sort_values('Number_of_Events', inplace=True)
excel_name = "smooth_line_data_no_host.xlsx"
df_line.to_excel(excel_name, index=False)
print(f"Data has been saved to {excel_name}")
print(df_line.head(10))

plt.figure(figsize=(10,6))
plt.plot(
df_line['Number_of_Events'],
df_line['Gold'],
marker='o', color='blue', linewidth=2
)
plt.title("Smooth Relationship: Number_of_Events vs. Gold (No Host Column)", fontsize=14)
plt.xlabel("Number_of_Events (integer)", fontsize=12)
plt.ylabel("Gold (simulated)", fontsize=12)
plt.xticks(df_line['Number_of_Events'])
plt.tight_layout()
plt.show()

##########################################################################

========== 示范:加入“教练加成”效果的折线图(示例数据) ==========

##########################################################################

固定随机种子,方便复现

np.random.seed(42)

国家与项目列表

countries = ['China', 'USA', 'Romania', 'Japan', 'Russia', 'Germany', 'Brazil']
sports = ['Volleyball', 'Gymnastics', 'Basketball', 'Football', 'Tennis', 'Swimming', 'Track & Field']

构造示例数据

medals_data = []
for country in countries:
for sport in sports:
gold = np.random.randint(0, 10) # 金牌
silver = np.random.randint(0, 10) # 银牌
bronze = np.random.randint(0, 10) # 铜牌
total = gold + silver + bronze
medals_data.append([country, sport, gold, silver, bronze, total])

df = pd.DataFrame(medals_data, columns=['Country','Sport','Gold','Silver','Bronze','Total'])

教练对部分国家/项目的加成

coach_effect = {
'China': {'Volleyball': 3},
'USA': {'Gymnastics': 4},
'Romania': {'Gymnastics': 5}
}

奖牌数据加上教练加成

for country, effect_dict in coach_effect.items():
for sport, effect in effect_dict.items():
df.loc[(df['Country']==country)&(df['Sport']==sport), 'Gold'] += effect

print("Updated Medal Data with Coach Effects:")
print(df.head(15)) # 打印前15行查看

--------让图表更平滑的关键:对 Sport 做整数映射--------

sports_sorted = sorted(sports) # 对项目按字母排序
sport_to_idx = {s: i for i, s in enumerate(sports_sorted)}

在原 df 上添加 SportIndex 列

df['SportIndex'] = df['Sport'].map(sport_to_idx)

排序后方便下面同时导出 Excel

df.sort_values(['Country','SportIndex'], inplace=True)

导出到 Excel 便于查看/复用

excel_output = "chart_data_coach_effect.xlsx"
df.to_excel(excel_output, index=False)
print(f"\nData used for chart saved to {excel_output}\n")

----------绘图:x=SportIndex, y=Gold,按国家分别画-----------

plt.figure(figsize=(10, 6))
for country in countries:
cdata = df[df['Country']==country]
plt.plot(cdata['SportIndex'], cdata['Gold'], marker='o', linewidth=2, label=country)

plt.title("Gold Medals by Sport (with Coach Effect, Smoothed X-axis)", fontsize=14)
plt.xlabel("Sport (Mapped to Index)", fontsize=12)
plt.ylabel("Gold Medals", fontsize=12)

设置 x 轴刻度:整数->项目名称

plt.xticks(range(len(sports_sorted)), sports_sorted, rotation=45)
plt.legend(title="Country")
plt.tight_layout()
plt.show()将输出的图表存为矢量图

Pensiero

I’m noting the user's request for generating a Python script that saves a collated image as a vector graphic file like PDF or SVG, instead of a raster image like PNG or JPG. The snippet will include instructions and the entire code for the graphs.

Crafting the solution

I’m working through the user's request for a Python script snippet to save a chart as a vector graphic (SVG or PDF), ensuring the final code includes comprehensive instructions and is in Chinese.

Thought about Olympic medal predictions and analysis,持续 15 秒

Risposta

下面给出一个示例,演示如何在 Matplotlib 中将生成的图表保存为矢量图(例如 SVG 或 PDF 格式)。只需要在 plt.show() 前或后,添加一行 plt.savefig("文件名.svg", format='svg')(或 PDF 格式),即可完成保存。


1. 为什么要使用矢量图?

  • 放大不失真: 矢量图以数学曲线描述图形,随意放大缩小都不会像位图那样出现马赛克。
  • 适合后期编辑: 在一些设计或排版软件中(如 Adobe Illustrator、Inkscape 等),可以对矢量格式的元素进行编辑、改变颜色、移动位置等,而不会损坏图表的质量。

常见的矢量图格式包括 SVGPDFEPS。Matplotlib 通常就支持直接导出这些格式。


2. 在代码中保存为矢量图的方式

以你给出的第一段奥运奖牌预测 & 进步退步分析代码为例,假设我们想把“Predicted Total Medals in 2028 (Vertical Bars)”这张柱状图保存为一个 SVG 矢量文件,那么只需要在调用 plt.show() 之前(或者之后,如果你想先可视化窗口再保存),加上一行 plt.savefig()。示例如下:

python
plt.figure(figsize=(12, 8)) sns.barplot(x='NOC', y='Predicted_Total', data=future_data.head(10), palette='viridis') plt.title('Predicted Total Medals in 2028 (Vertical Bars)') plt.xlabel('Country (NOC)') plt.ylabel('Predicted Total Medals') plt.xticks(rotation=45, ha='right') plt.tight_layout() # 保存为矢量图 plt.savefig("predicted_total_medals_2028.svg", format='svg', dpi=300) plt.show()
  • format='svg' 指定输出格式为 SVG。
  • dpi=300 常用于指定分辨率;对于矢量图并非必须,但一些混合了文本、点阵或某些 Artist 对象的图表,用适当的 dpi 也能帮助增强导出的效果。

同理,如果想保存为 PDF,可将 format='svg' 改为 format='pdf'

python
plt.savefig("predicted_total_medals_2028.pdf", format='pdf', dpi=300)

注意:如果在同一个 plt 环境下,多次生成不同图表,需要在每一次生成图表后,都进行一次 plt.savefig(),再进行 plt.show() 或者用多个 figure+axes 控制流程,以免后续的图表覆盖前面的输出。


3. 其它示例图保存为矢量图

(1)“断轴”示例

原始代码示例(简化),在最后增加保存为 SVG:

python
fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True, figsize=(8,6)) # ... 省略绘图逻辑 ... plt.tight_layout() # 保存为矢量图(示例) plt.savefig("broken_axis_example.svg", format='svg', dpi=300) plt.show()

(2)Part A 生成的折线图

例如在 “Gold to Event Ratio per Year” 图中,添加如下代码:

python
plt.figure(figsize=(12, 6)) plt.plot(yearly_summary['Year'], yearly_summary['Gold_to_Event_Ratio'], marker='o', color='purple') plt.title("Gold to Event Ratio per Year (1896-2024)", fontsize=14) plt.xlabel("Year", fontsize=12) plt.ylabel("Gold to Event Ratio", fontsize=12) plt.tight_layout() # 保存为矢量图 plt.savefig("gold_to_event_ratio.svg", format='svg', dpi=300) plt.show()

(3)Part B 生成的“平滑”模拟数据折线图

python
plt.figure(figsize=(10,6)) plt.plot( df_line['Number_of_Events'], df_line['Gold'], marker='o', color='blue', linewidth=2 ) plt.title("Smooth Relationship: Number_of_Events vs. Gold (No Host Column)", fontsize=14) plt.xlabel("Number_of_Events (integer)", fontsize=12) plt.ylabel("Gold (simulated)", fontsize=12) plt.xticks(df_line['Number_of_Events']) plt.tight_layout() # 保存为矢量图 plt.savefig("smooth_line_data_no_host.svg", format='svg', dpi=300) plt.show()

(4)“教练加成”折线图示例

python
plt.figure(figsize=(10, 6)) for country in countries: cdata = df[df['Country']==country] plt.plot(cdata['SportIndex'], cdata['Gold'], marker='o', linewidth=2, label=country) plt.title("Gold Medals by Sport (with Coach Effect, Smoothed X-axis)", fontsize=14) plt.xlabel("Sport (Mapped to Index)", fontsize=12) plt.ylabel("Gold Medals", fontsize=12) plt.xticks(range(len(sports_sorted)), sports_sorted, rotation=45) plt.legend(title="Country") plt.tight_layout() # 保存为矢量图 plt.savefig("gold_medals_by_sport_coach_effect.svg", format='svg', dpi=300) plt.show()

4. 小结

  1. 在 Matplotlib 中保存矢量图只需在绘图后、plt.show() 前(或后)调用 plt.savefig("文件名.扩展名", format="对应格式") 即可。
  2. 如果要保存为 SVG,扩展名一般用 .svg;若要保存 PDF,则可使用 .pdf;也可以使用 .eps.ps 等格式。
  3. 示例
    python
    plt.savefig("my_figure.svg", format='svg', dpi=300) plt.savefig("my_figure.pdf", format='pdf', dpi=300)

这样,你就可以在后续的文档、幻灯片、出版物等需要放大或排版的场景下,使用矢量图而不失真。祝你使用愉快!

Domanda

输出完整代码啊

Pensiero

Combining code segments

The user wants all code segments merged or kept separate, and they instruct to include a saving line for the vector image.

Integrating code and saving

I'm piecing together the entire code, ensuring each plot's vector image is saved in .svg format with distinct filenames, after their generation.

Integrating multiple plots

I’m gathering all plots into a single script, ensuring each plot saves its vector image in .svg format. Each will have a unique filename to keep things clear.

Finalizing the integration

I’m crafting the final code block by incorporating savefig before plt.show() for each figure, ensuring all elements are included and uniquely labeled for clarity.

Thought about saving plots as vector graphics,持续 20 秒

Risposta

下面给出一份完整示例代码,包含你原有的所有分析与绘图步骤,并在每个需要输出图表的地方插入了将图表保存为矢量图(SVG 格式)的示例。你可以根据需要将 plt.savefig("xxx.svg", format="svg", dpi=300) 调整到任意文件名或路径,并选择合适的格式(svg/pdf/eps 等)和分辨率 (dpi)。

以下代码可以直接运行,建议你在运行之前先确保本地文件路径(如 CSV 的读取、Excel 的输出路径)已经调整为符合你的实际情况。


完整代码(内含保存为矢量图的示例)

python
import os import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns import math from sklearn.linear_model import LinearRegression from sklearn.model_selection import train_test_split from sklearn.metrics import mean_squared_error ########################################################################## # 1) 第一段代码: 奥运奖牌预测 & 进步退步分析 ########################################################################## # 读取 athletes & medal_counts athletes = pd.read_csv('summerOly_athletes.csv', encoding='ISO-8859-1') medal_counts = pd.read_csv('summerOly_medal_counts.csv', encoding='ISO-8859-1') # Merge & Preprocess medal_summary = medal_counts.groupby(['Year','NOC'], as_index=False).agg({ 'Gold':'sum','Silver':'sum','Bronze':'sum','Total':'sum' }) athlete_summary = athletes.groupby(['Year','NOC'], as_index=False).size().rename(columns={'size':'Athletes'}) data = pd.merge(medal_summary, athlete_summary, on=['Year','NOC'], how='left').fillna(0) # Rolling historical features data.sort_values(['NOC','Year'], inplace=True) data['Past_Gold_Avg'] = data.groupby('NOC')['Gold'].transform( lambda x: x.shift().rolling(window=3, min_periods=1).mean()) data['Past_Total_Avg'] = data.groupby('NOC')['Total'].transform( lambda x: x.shift().rolling(window=3, min_periods=1).mean()) data['Past_Gold_Sum'] = data.groupby('NOC')['Gold'].transform( lambda x: x.shift().rolling(window=3, min_periods=1).sum()) data['Past_Total_Sum'] = data.groupby('NOC')['Total'].transform( lambda x: x.shift().rolling(window=3, min_periods=1).sum()) data[['Past_Gold_Avg','Past_Total_Avg','Past_Gold_Sum','Past_Total_Sum']] = \ data[['Past_Gold_Avg','Past_Total_Avg','Past_Gold_Sum','Past_Total_Sum']].fillna(0) features = ['Past_Gold_Avg','Past_Total_Avg','Past_Gold_Sum','Past_Total_Sum'] target_gold = 'Gold' target_total = 'Total' def build_model(df, feats, target): X = df[feats] y = df[target] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) model = LinearRegression() model.fit(X_train, y_train) y_pred = model.predict(X_test) mse = mean_squared_error(y_test, y_pred) print(f"Model for {target}: MSE = {mse}") return model model_gold = build_model(data, features, target_gold) model_total = build_model(data, features, target_total) # Predict for 2028 unique_nocs = data['NOC'].unique() df_2024 = data[data['Year']==2024].copy() group_2024 = df_2024.groupby('NOC', as_index=False)[features].mean() future_data = pd.DataFrame({'NOC': unique_nocs}) future_data = pd.merge(future_data, group_2024, on='NOC', how='left').fillna(0) pred_gold = model_gold.predict(future_data[features]) pred_total = model_total.predict(future_data[features]) pred_gold = np.clip(pred_gold, a_min=0, a_max=None) pred_total = np.clip(pred_total, a_min=0, a_max=None) future_data['Predicted_Gold'] = pd.Series(pred_gold).round().astype(int) future_data['Predicted_Total'] = pd.Series(pred_total).round().astype(int) gold_res = model_gold.predict(data[features]) - data[target_gold] total_res = model_total.predict(data[features]) - data[target_total] gold_std = gold_res.std() total_std = total_res.std() future_data['Gold_Lower'] = (future_data['Predicted_Gold'] - 2*gold_std).clip(lower=0).round().astype(int) future_data['Gold_Upper'] = (future_data['Predicted_Gold'] + 2*gold_std).clip(lower=0).round().astype(int) future_data['Total_Lower'] = (future_data['Predicted_Total'] - 2*total_std).clip(lower=0).round().astype(int) future_data['Total_Upper'] = (future_data['Predicted_Total'] + 2*total_std).clip(lower=0).round().astype(int) future_data.sort_values(by='Predicted_Total', ascending=False, inplace=True) print("Predicted Medal Table for 2028 Los Angeles Olympics:") print( future_data[['NOC','Predicted_Gold','Gold_Lower','Gold_Upper', 'Predicted_Total','Total_Lower','Total_Upper']] ) future_data.to_csv('Predicted_Medal_Table_2028.csv', index=False) print("Results saved to 'Predicted_Medal_Table_2028.csv'") # ---- 图表 1: Predicted Total Medals ---- plt.figure(figsize=(12, 8)) sns.barplot(x='NOC', y='Predicted_Total', data=future_data.head(10), palette='viridis') plt.title('Predicted Total Medals in 2028 (Vertical Bars)') plt.xlabel('Country (NOC)') plt.ylabel('Predicted Total Medals') plt.xticks(rotation=45, ha='right') plt.tight_layout() # 保存为矢量图 (示例) plt.savefig("predicted_total_medals_2028.svg", format='svg', dpi=300) plt.show() future_data['Gold_History'] = data.groupby('NOC')['Past_Gold_Avg'].mean().reindex(unique_nocs).fillna(0).values future_data['Total_History'] = data.groupby('NOC')['Past_Total_Avg'].mean().reindex(unique_nocs).fillna(0).values future_data['Gold_Progress'] = future_data['Predicted_Gold'] - future_data['Gold_History'] future_data['Total_Progress'] = future_data['Predicted_Total'] - future_data['Total_History'] future_data['Gold_Trend'] = np.where(future_data['Gold_Progress']>0, 'Progress','Decline') future_data['Total_Trend'] = np.where(future_data['Total_Progress']>0, 'Progress','Decline') progress_gold = future_data[['NOC','Predicted_Gold','Gold_Progress','Gold_Trend']]\ .sort_values('Gold_Progress', ascending=False) decline_gold = future_data[['NOC','Predicted_Gold','Gold_Progress','Gold_Trend']]\ .sort_values('Gold_Progress', ascending=True) progress_total = future_data[['NOC','Predicted_Total','Total_Progress','Total_Trend']]\ .sort_values('Total_Progress', ascending=False) decline_total = future_data[['NOC','Predicted_Total','Total_Progress','Total_Trend']]\ .sort_values('Total_Progress', ascending=True) print("\nCountries Most Likely to Improve in Gold:") print(progress_gold.head(10)) print("\nCountries Most Likely to Decline in Gold:") print(decline_gold.head(10)) print("\nCountries Most Likely to Improve in Total Medals:") print(progress_total.head(10)) print("\nCountries Most Likely to Decline in Total Medals:") print(decline_total.head(10)) # ---- 图表 2: Top 10 Countries Likely to Improve in Gold ---- plt.figure(figsize=(12, 8)) sns.barplot(x='NOC', y='Gold_Progress', data=progress_gold.head(10), palette='Blues') plt.title('Top 10 Countries Likely to Improve in Gold (Vertical Bars)') plt.xlabel('Country (NOC)') plt.ylabel('Gold Medal Progress') plt.xticks(rotation=45, ha='right') plt.tight_layout() plt.savefig("top10_improve_gold.svg", format='svg', dpi=300) plt.show() # ---- 图表 3: Top 10 Countries Likely to Decline in Gold ---- plt.figure(figsize=(12, 8)) sns.barplot(x='NOC', y='Gold_Progress', data=decline_gold.head(10), palette='Reds') plt.title('Top 10 Countries Likely to Decline in Gold (Vertical Bars)') plt.xlabel('Country (NOC)') plt.ylabel('Gold Medal Decline') plt.xticks(rotation=45, ha='right') plt.tight_layout() plt.savefig("top10_decline_gold.svg", format='svg', dpi=300) plt.show() # ---- 图表 4: Top 10 Countries Likely to Improve in Total Medals ---- plt.figure(figsize=(12, 8)) sns.barplot(x='NOC', y='Total_Progress', data=progress_total.head(10), palette='Blues') plt.title('Top 10 Countries Likely to Improve in Total Medals (Vertical Bars)') plt.xlabel('Country (NOC)') plt.ylabel('Total Medal Progress') plt.xticks(rotation=45, ha='right') plt.tight_layout() plt.savefig("top10_improve_total.svg", format='svg', dpi=300) plt.show() # ---- 图表 5: Top 10 Countries Likely to Decline in Total Medals ---- plt.figure(figsize=(12, 8)) sns.barplot(x='NOC', y='Total_Progress', data=decline_total.head(10), palette='Reds') plt.title('Top 10 Countries Likely to Decline in Total Medals (Vertical Bars)') plt.xlabel('Country (NOC)') plt.ylabel('Total Medal Decline') plt.xticks(rotation=45, ha='right') plt.tight_layout() plt.savefig("top10_decline_total.svg", format='svg', dpi=300) plt.show() # ---- 图表 6: Predicted Gold Share (Pie Chart) ---- future_data_gold_sorted = future_data.sort_values('Predicted_Gold', ascending=False) top10_gold = future_data_gold_sorted.head(10) others_gold = future_data_gold_sorted.iloc[10:]['Predicted_Gold'].sum() labels = list(top10_gold['NOC'].values) + ['Others'] values = list(top10_gold['Predicted_Gold'].values) + [others_gold] top_colors = sns.color_palette('Set2', n_colors=len(top10_gold)) others_color = [(0.5,0.5,0.5)] colors = top_colors + others_color explode = [0]*(len(top10_gold)) + [0.1] plt.figure(figsize=(8,8)) plt.pie( values, labels=labels, colors=colors, explode=explode, autopct='%1.1f%%', startangle=160, wedgeprops={'alpha':0.9}, labeldistance=1.12, pctdistance=0.75 ) plt.title("Predicted Gold Share: Top 10 vs. Others (2D Pie)") plt.axis('equal') plt.tight_layout() plt.savefig("predicted_gold_share_top10_vs_others.svg", format='svg', dpi=300) plt.show() ########################################################################## # 2) 第二段代码: “断轴”示例 (保留原逻辑 + 输出) ########################################################################## countries = ["Yugoslavia","Turkey","Croatia","Canada","Costa Rica", "Latvia","Indonesia","Nigeria","Kyrgyzstan","Finland"] values = [0.67,0.65,0.52,0.50,0.49,0.48,0.48,0.47,0.47,0.46] gold_prob_mod = pd.Series(data=values, index=countries) x_labels = gold_prob_mod.index x_vals = np.arange(len(x_labels)) fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True, figsize=(8,6)) fig.subplots_adjust(hspace=0.05) ax1.bar(x_vals, gold_prob_mod, color='skyblue', edgecolor='black') ax1.set_ylim(0.45, 0.7) ax1.spines['bottom'].set_visible(False) ax1.tick_params(labelbottom=False) ax2.bar(x_vals, gold_prob_mod, color='skyblue', edgecolor='black') ax2.set_ylim(0, 0.4) d = .01 kwargs = dict(transform=ax1.transAxes, color='k', clip_on=False) ax1.plot((-d, +d), (-d, +d), **kwargs) ax1.plot((1 - d, 1 + d), (-d, +d), **kwargs) kwargs = dict(transform=ax2.transAxes, color='k', clip_on=False) ax2.plot((-d, +d), (1 - d, 1 + d), **kwargs) ax2.plot((1 - d, 1 + d), (1 - d, 1 + d), **kwargs) ax2.set_xticks(x_vals) ax2.set_xticklabels(x_labels, rotation=45, ha='right') ax2.set_xlabel("Country (NOC)") ax2.set_ylabel("Probability of 'trend>0'") ax1.set_title("Top 10 Zero-Gold Countries (Broken Y-Axis)") plt.tight_layout() # 保存为矢量图 plt.savefig("broken_axis_example.svg", format='svg', dpi=300) plt.show() ########################################################################## # ========== PART A: 生成 yearly_summary 并画两张图 ========== ########################################################################## base_dir = r"D:\浏览器下载\pycharm\olympic\my_olympic_project\.venv" programs_file_path = os.path.join(base_dir, 'summerOly_programs.csv') medal_counts_file_path = os.path.join(base_dir, 'summerOly_medal_counts.csv') output_excel = os.path.join(base_dir, 'yearly_summary.xlsx') programs_df = pd.read_csv(programs_file_path, encoding='ISO-8859-1') medal_counts_df = pd.read_csv(medal_counts_file_path, encoding='ISO-8859-1') programs_df_cleaned = programs_df.loc[:, ~programs_df.columns.str.contains("Code|Sport|Discipline|Sports Governing Body")] programs_df_cleaned = programs_df_cleaned.rename(columns=lambda x: x.strip().replace('*','') if isinstance(x, str) else x) programs_df_cleaned = programs_df_cleaned.apply(pd.to_numeric, errors='coerce') programs_melted_cleaned = programs_df_cleaned.melt(var_name='Year', value_name='Number_of_Events') programs_melted_cleaned['Year'] = pd.to_numeric(programs_melted_cleaned['Year'], errors='coerce', downcast='integer') medal_counts_per_year = medal_counts_df.groupby(['Year','NOC'])['Gold'].sum().reset_index() merged_data_cleaned = pd.merge(medal_counts_per_year, programs_melted_cleaned, how='left', on='Year') yearly_summary = merged_data_cleaned.groupby('Year').agg({ 'Number_of_Events':'sum', 'Gold':'sum' }).reset_index() yearly_summary['Gold_to_Event_Ratio'] = yearly_summary['Gold'] / yearly_summary['Number_of_Events'] yearly_summary['Gold_to_Event_Ratio'] = yearly_summary['Gold_to_Event_Ratio'].fillna(0) yearly_summary.to_excel(output_excel, index=False) print(f"yearly_summary 已保存至: {output_excel}") print(yearly_summary.head(10)) # ---- 图表 1: Gold to Event Ratio per Year ---- plt.figure(figsize=(12, 6)) plt.plot(yearly_summary['Year'], yearly_summary['Gold_to_Event_Ratio'], marker='o', color='purple') plt.title("Gold to Event Ratio per Year (1896-2024)", fontsize=14) plt.xlabel("Year", fontsize=12) plt.ylabel("Gold to Event Ratio", fontsize=12) plt.tight_layout() plt.savefig("gold_to_event_ratio_per_year.svg", format='svg', dpi=300) plt.show() # ---- 图表 2: Number_of_Events vs Gold ---- plt.figure(figsize=(12, 6)) plt.plot(yearly_summary['Year'], yearly_summary['Number_of_Events'], label="Number of Events", marker='o', color='b') plt.plot(yearly_summary['Year'], yearly_summary['Gold'], label="Gold Medals", marker='o', color='g') plt.title("Relationship between Number of Events and Gold Medal Counts (1896-2024)", fontsize=14) plt.xlabel("Year", fontsize=12) plt.ylabel("Count", fontsize=12) plt.legend(title="Legend") plt.tight_layout() plt.savefig("events_vs_gold.svg", format='svg', dpi=300) plt.show() ########################################################################## # ========== PART B: 生成“平滑”模拟数据并画折线图 ========== ########################################################################## N = 20 x_start = 10 x_vals = np.arange(x_start, x_start + N) gold_list = [] rng = np.random.default_rng(2028) for x in x_vals: base = 2*x + 10 wave = math.sin(x/2)*3 y = round(base + wave) gold_list.append(y) df_line = pd.DataFrame({ 'Number_of_Events': x_vals, 'Gold': gold_list }) df_line.sort_values('Number_of_Events', inplace=True) excel_name = "smooth_line_data_no_host.xlsx" df_line.to_excel(excel_name, index=False) print(f"Data has been saved to {excel_name}") print(df_line.head(10)) plt.figure(figsize=(10,6)) plt.plot( df_line['Number_of_Events'], df_line['Gold'], marker='o', color='blue', linewidth=2 ) plt.title("Smooth Relationship: Number_of_Events vs. Gold (No Host Column)", fontsize=14) plt.xlabel("Number_of_Events (integer)", fontsize=12) plt.ylabel("Gold (simulated)", fontsize=12) plt.xticks(df_line['Number_of_Events']) plt.tight_layout() plt.savefig("smooth_line_relationship.svg", format='svg', dpi=300) plt.show() ########################################################################## # ========== 示范:加入“教练加成”效果的折线图(示例数据) ========== ########################################################################## # 固定随机种子,方便复现 np.random.seed(42) # 国家与项目列表 countries = ['China', 'USA', 'Romania', 'Japan', 'Russia', 'Germany', 'Brazil'] sports = ['Volleyball', 'Gymnastics', 'Basketball', 'Football', 'Tennis', 'Swimming', 'Track & Field'] # 构造示例数据 medals_data = [] for country in countries: for sport in sports: gold = np.random.randint(0, 10) # 金牌 silver = np.random.randint(0, 10) # 银牌 bronze = np.random.randint(0, 10) # 铜牌 total = gold + silver + bronze medals_data.append([country, sport, gold, silver, bronze, total]) df = pd.DataFrame(medals_data, columns=['Country','Sport','Gold','Silver','Bronze','Total']) # 教练对部分国家/项目的加成 coach_effect = { 'China': {'Volleyball': 3}, 'USA': {'Gymnastics': 4}, 'Romania': {'Gymnastics': 5} } # 奖牌数据加上教练加成 for country, effect_dict in coach_effect.items(): for sport, effect in effect_dict.items(): df.loc[(df['Country']==country)&(df['Sport']==sport), 'Gold'] += effect print("Updated Medal Data with Coach Effects:") print(df.head(15)) # 打印前15行查看 # --------让图表更平滑的关键:对 Sport 做整数映射-------- sports_sorted = sorted(sports) # 对项目按字母排序 sport_to_idx = {s: i for i, s in enumerate(sports_sorted)} df['SportIndex'] = df['Sport'].map(sport_to_idx) df.sort_values(['Country','SportIndex'], inplace=True) excel_output = "chart_data_coach_effect.xlsx" df.to_excel(excel_output, index=False) print(f"\nData used for chart saved to {excel_output}\n") # ----------绘图:x=SportIndex, y=Gold,按国家分别画----------- plt.figure(figsize=(10, 6)) for country in countries: cdata = df[df['Country']==country] plt.plot(cdata['SportIndex'], cdata['Gold'], marker='o', linewidth=2, label=country) plt.title("Gold Medals by Sport (with Coach Effect, Smoothed X-axis)", fontsize=14) plt.xlabel("Sport (Mapped to Index)", fontsize=12) plt.ylabel("Gold Medals", fontsize=12) # 设置 x 轴刻度:整数 -> 项目名称 plt.xticks(range(len(sports_sorted)), sports_sorted, rotation=45) plt.legend(title="Country") plt.tight_layout() # 保存为矢量图 plt.savefig("gold_medals_with_coach_effect.svg", format='svg', dpi=300) plt.show()

说明

  1. 关键改动:在每个 plt.show() 之前,插入了 plt.savefig("xxx.svg", format='svg', dpi=300),这样就可以把图表导出为 SVG 矢量图。你也可以换成 pdfeps,例如:
    python
    plt.savefig("my_figure.pdf", format='pdf', dpi=300)
  2. 文件路径:脚本里有一些 CSV/XLSX 文件的读取与输出路径,需要你在实际使用时根据本地环境调整,确保文件路径正确可用。
  3. 多图保存:如果你想要一口气生成并保存多张图,无需每次都 plt.show(),可以将所有 plt.savefig() 调用放在适当位置,然后在最后统一 plt.show();也可以在每张图后面都分别调用一次 plt.show()savefig()。这完全取决于个人偏好与绘图流程。

这样就可以将每张图都保存为矢量图了!祝你使用愉快。

Domanda

5.1 问题1:各国奖牌数预测模型翻译这个为英文

Pensiero

Translating the problem

I’m mapping out the translation for "5.1 问题1:各国奖牌数预测模型." Considering nuances such as "各国" (each country), "奖牌数" (number of medals), and "预测模型" (prediction model).

Thought about medal prediction model,持续 11 秒

Risposta

5.1 Problem 1: Medal Count Prediction Model for Each Country

Domanda

5.3 问题3:奥运会奖牌数的其他原始见解及其对各国奥林匹克委员会的启示
5.2 问题2:“伟大教练”效应分析模型 翻译

Pensiero

5.3 Problem 3: Other Raw Insights on Olympic Medal Counts and Their Implications for National Olympic Committees

5.2 Problem 2: "Great Coach" Effect Analysis Model,持续 4 秒

Risposta

5.2 Question 2: “Great Coach” Effect Analysis Model
5.3 Question 3: Other Original Insights on Olympic Medal Counts and Their Implications for National Olympic Committees

Condividi questa Q&A