def initialize_session_state(): if 'data' not in st.session_state: st.session_state.data = None if 'processed_data' not in st.session_state: st.session_state.processed_data = None if 'slicers' not in st.session_state: st.session_state.slicers = {} if 'x_var' not in st.session_state: st.session_state.x_var = None if 'y_var' not in st.session_state: st.session_state.y_var = None if 'analysis_performed' not in st.session_state: st.session_state.analysis_performed = False def create_slicers(data): categorical_columns = data.select_dtypes(include=['object', 'category']).columns for col in categorical_columns: if data[col].nunique() <= 10: # 고유값이 10개 이하인 경우에만 슬라이서 생성 if col not in st.session_state.slicers: st.session_state.slicers[col] = sorted(data[col].unique()) st.session_state.slicers[col] = st.multiselect( f"{col} 선택", options=sorted(data[col].unique()), default=st.session_state.slicers[col] ) def apply_slicers(data): for col, selected_values in st.session_state.slicers.items(): if selected_values: data = data[data[col].isin(selected_values)] return data def perform_analysis(data): st.header("탐색적 데이터 분석") # 슬라이서 생성 및 적용 create_slicers(data) filtered_data = apply_slicers(data) # 요약 통계 st.write("요약 통계:") st.write(filtered_data.describe()) # 상관관계 히트맵 st.write("상관관계 히트맵:") numeric_data = filtered_data.select_dtypes(include=['float64', 'int64']) if not numeric_data.empty: fig = px.imshow(numeric_data.corr(), color_continuous_scale='RdBu_r', zmin=-1, zmax=1) fig.update_layout(title='상관관계 히트맵') st.plotly_chart(fig) else: st.write("상관관계 히트맵을 그릴 수 있는 숫자형 열이 없습니다.") # 사용자가 선택한 두 변수에 대한 산점도 및 회귀 분석 st.subheader("두 변수 간의 관계 분석") numeric_columns = filtered_data.select_dtypes(include=['float64', 'int64']).columns st.session_state.x_var = st.selectbox("X축 변수 선택", options=numeric_columns, key='x_var_select', index=numeric_columns.get_loc(st.session_state.x_var) if st.session_state.x_var in numeric_columns else 0) y_options = [col for col in numeric_columns if col != st.session_state.x_var] st.session_state.y_var = st.selectbox("Y축 변수 선택", options=y_options, key='y_var_select', index=y_options.index(st.session_state.y_var) if st.session_state.y_var in y_options else 0) if st.session_state.x_var and st.session_state.y_var: fig = px.scatter(filtered_data, x=st.session_state.x_var, y=st.session_state.y_var, color='반' if '반' in filtered_data.columns else None) # 회귀선 추가 x = filtered_data[st.session_state.x_var] y = filtered_data[st.session_state.y_var] slope, intercept, r_value, p_value, std_err = stats.linregress(x, y) line_x = np.array([x.min(), x.max()]) line_y = slope * line_x + intercept fig.add_trace(go.Scatter(x=line_x, y=line_y, mode='lines', name='회귀선')) r_squared = r_value ** 2 fig.update_layout( title=f'{st.session_state.x_var}와 {st.session_state.y_var}의 관계 (R-squared: {r_squared:.4f})', xaxis_title=st.session_state.x_var, yaxis_title=st.session_state.y_var, annotations=[ dict( x=0.5, y=1.05, xref='paper', yref='paper', text=f'R-squared: {r_squared:.4f}', showarrow=False, ) ] ) st.plotly_chart(fig) # 추가 통계 정보 st.write(f"상관계수: {r_value:.4f}") st.write(f"p-value: {p_value:.4f}") st.write(f"표준 오차: {std_err:.4f}") st.session_state.analysis_performed = True def main(): st.title("인터랙티브 EDA 툴킷") initialize_session_state() if st.session_state.data is None: data_input_method = st.radio("데이터 입력 방법 선택:", ("파일 업로드", "수동 입력")) if data_input_method == "파일 업로드": uploaded_file = st.file_uploader("CSV, XLS, 또는 XLSX 파일을 선택하세요", type=["csv", "xls", "xlsx"]) if uploaded_file is not None: st.session_state.data = load_data(uploaded_file) else: st.session_state.data = manual_data_entry() if st.session_state.data is not None: st.subheader("데이터 미리보기 및 수정") st.write("데이터를 확인하고 필요한 경우 수정하세요:") edited_data = st.data_editor(st.session_state.data, num_rows="dynamic") if st.button("데이터 분석 시작") or st.session_state.analysis_performed: if not st.session_state.analysis_performed: st.session_state.processed_data = preprocess_data(edited_data) perform_analysis(st.session_state.processed_data) if __name__ == "__main__": main()