Spaces:
Sleeping
Sleeping
import streamlit as st | |
import pandas as pd | |
import numpy as np | |
# 设置页面布局为宽屏模式,并设置页面标题 | |
st.set_page_config(layout="wide", page_title="影城效率分析 - 最终版") | |
def clean_movie_title(title): | |
""" | |
清理并规范化电影标题,移除版本、语言等标识以便合并统计。 | |
""" | |
if not isinstance(title, str): | |
return title | |
suffixes_to_remove = [ | |
'2D', '3D', '4D', '4K', 'IMAX', 'CINITY', '杜比', '巨幕', | |
'国语', '英语', '粤语', '日语', '原版', '修复版', | |
'(国)', '(英)', '(粤)' | |
] | |
parts = title.split() | |
cleaned_parts = [p for p in parts if p.upper() not in [s.upper() for s in suffixes_to_remove]] | |
if not cleaned_parts: | |
return title | |
return ' '.join(cleaned_parts).strip() | |
def style_efficiency(row): | |
""" | |
根据效率值高亮特定行。 | |
如果座次效率或场次效率 < 0.5 或 > 1.5,则高亮为淡黄色。 | |
""" | |
highlight = 'background-color: #FFFFE0;' | |
default = '' | |
seat_efficiency = row.get('座次效率', 0) | |
session_efficiency = row.get('场次效率', 0) | |
if (seat_efficiency < 0.5 or seat_efficiency > 1.5 or | |
session_efficiency < 0.5 or session_efficiency > 1.5): | |
return [highlight] * len(row) | |
return [default] * len(row) | |
def process_and_analyze_data(df): | |
""" | |
核心数据处理与分析函数。 | |
""" | |
if df.empty: | |
return pd.DataFrame() | |
analysis_df = df.groupby('影片名称_清理后').agg( | |
座位数=('座位数', 'sum'), | |
场次=('影片名称_清理后', 'size'), | |
票房=('总收入', 'sum'), | |
人次=('总人次', 'sum') | |
).reset_index() | |
analysis_df.rename(columns={'影片名称_清理后': '影片'}, inplace=True) | |
analysis_df = analysis_df.sort_values(by='票房', ascending=False).reset_index(drop=True) | |
total_seats = analysis_df['座位数'].sum() | |
total_sessions = analysis_df['场次'].sum() | |
total_revenue = analysis_df['票房'].sum() | |
analysis_df['均价'] = np.divide(analysis_df['票房'], analysis_df['人次']).fillna(0) | |
analysis_df['座次比'] = np.divide(analysis_df['座位数'], total_seats).fillna(0) | |
analysis_df['场次比'] = np.divide(analysis_df['场次'], total_sessions).fillna(0) | |
analysis_df['票房比'] = np.divide(analysis_df['票房'], total_revenue).fillna(0) | |
analysis_df['座次效率'] = np.divide(analysis_df['票房比'], analysis_df['座次比']).fillna(0) | |
analysis_df['场次效率'] = np.divide(analysis_df['票房比'], analysis_df['场次比']).fillna(0) | |
# **优化1:移除“序号”列的定义** | |
final_columns = [ | |
'影片', '座位数', '场次', '票房', '人次', '均价', | |
'座次比', '场次比', '票房比', '座次效率', '场次效率' | |
] | |
analysis_df = analysis_df[final_columns] | |
return analysis_df | |
# --- Streamlit 用户界面 --- | |
st.title('排片效率分析') | |
st.write("上传 `影片映出日累计报表.xlsx` 文件。") | |
uploaded_file = st.file_uploader("请在此处上传 Excel 文件", type=['xlsx', 'xls', 'csv']) | |
if uploaded_file is not None: | |
try: | |
df = pd.read_excel(uploaded_file, skiprows=3, header=None) | |
df.rename(columns={ | |
0: '影片名称', 2: '放映时间', 5: '总人次', 6: '总收入', 7: '座位数' | |
}, inplace=True) | |
required_cols = ['影片名称', '放映时间', '座位数', '总收入', '总人次'] | |
df = df[required_cols] | |
df.dropna(subset=['影片名称', '放映时间'], inplace=True) | |
for col in ['座位数', '总收入', '总人次']: | |
df[col] = pd.to_numeric(df[col], errors='coerce').fillna(0) | |
df['放映时间'] = pd.to_datetime(df['放映时间'], format='%H:%M:%S', errors='coerce').dt.time | |
df.dropna(subset=['放映时间'], inplace=True) | |
df['影片名称_清理后'] = df['影片名称'].apply(clean_movie_title) | |
st.toast("文件上传成功,数据已按规则处理!", icon="🎉") | |
format_config = { | |
'座位数': '{:,.0f}', '场次': '{:,.0f}', '人次': '{:,.0f}', | |
'票房': '{:,.2f}', '均价': '{:.2f}', '座次比': '{:.2%}', '场次比': '{:.2%}', | |
'票房比': '{:.2%}', '座次效率': '{:.2f}', '场次效率': '{:.2f}', | |
} | |
# --- 1. 全天数据分析 --- | |
st.header("全天排片效率分析") | |
full_day_analysis = process_and_analyze_data(df.copy()) | |
if not full_day_analysis.empty: | |
table_height = (len(full_day_analysis) + 1) * 35 + 3 | |
# **优化2:使用 .hide(axis="index") 隐藏默认序号列** | |
st.dataframe( | |
full_day_analysis.style.format(format_config).apply(style_efficiency, axis=1).hide(axis="index"), | |
height=table_height, | |
use_container_width=True | |
) | |
else: | |
st.warning("全天数据不足,无法生成分析报告。") | |
# --- 2. 黄金时段数据分析 --- | |
st.header("黄金时段 (14:00 - 21:00) 排片效率分析") | |
start_time = pd.to_datetime('14:00:00').time() | |
end_time = pd.to_datetime('21:00:00').time() | |
prime_time_df = df[df['放映时间'].between(start_time, end_time)] | |
prime_time_analysis = process_and_analyze_data(prime_time_df.copy()) | |
if not prime_time_analysis.empty: | |
table_height_prime = (len(prime_time_analysis) + 1) * 35 + 3 | |
# **优化2:同样隐藏黄金时段表格的默认序号** | |
st.dataframe( | |
prime_time_analysis.style.format(format_config).apply(style_efficiency, axis=1).hide(axis="index"), | |
height=table_height_prime, | |
use_container_width=True | |
) | |
else: | |
st.warning("黄金时段内没有有效场次数据,无法生成分析报告。") | |
# --- 3. 一键复制影片列表 --- | |
if not full_day_analysis.empty: | |
st.header("复制当日影片列表") | |
movie_titles = full_day_analysis['影片'].tolist() | |
formatted_titles = ''.join([f'《{title}》' for title in movie_titles]) | |
st.code(formatted_titles, language='text') | |
except Exception as e: | |
st.error(f"处理文件时出错: {e}") | |
st.warning("请确保上传的文件是'影片映出日累计报表.xlsx',并且格式正确。") | |
else: | |
st.info("请上传文件以开始分析。") |