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 # 将标题按第一个空格分割,并只取第一部分 return title.split(' ', 1)[0] 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) 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 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("黄金时段排片效率分析") 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 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("请上传文件以开始分析。")