INSERT INTO users (name, email, age, city) SELECT '새 사용자', 'test메일', 25, 'seoul' WHERE NOT EXISTS ( SELECT 1 FROM users WHERE email = 'test메일' ); 이 쿼리를 처음에 설명해 주실 때 두 개의 프로세스가 동시에 데이터를 확인하고 삽입하려 할 때 경쟁상태가 발생할 수 있다라고 하셨다가 뒤에 이 방식은 사실상 경쟁상태에 무관하다고 정정해주셨는데 그럼 두 개의 프로세스가 동시에 데이터를 확인하고 삽입하려 했을때 무관하다는 의미인가요?? 왜 무관한지 잘 모르겠습니다.
저장은 되게 되었습니다. 근데 이게 ai가 db에 그냥 아무 데이터나 넣게 학습 시키게끔 바꾼건지 잘 모르겠습니다. # 예전: 종목 목록을 만든 뒤 바로 스케일링했다. # 지금: 숫자가 하나도 없는 칸은 학습에서 뺀다. def columns_with_numbers(frame, columns): kept = [] dropped = [] for col in columns: numeric = pd.to _numeric(frame[col], errors='coerce') if col in frame.columns else pd.Series(dtype=float) if numeric.notna().any() and np.isfinite( numeric.to _numpy(dtype=float, na_value=np.nan)).any(): kept.append(col) else: dropped.append(col) return kept, dropped target_columns, dropped_targets = columns_with_numbers(data, target_columns) economic_features, dropped_econ = columns_with_numbers(data, economic_features) dropped_columns = dropped_targets + dropped_econ if dropped_columns: print(f"값이 없어 학습에서 뺀 칸: {dropped_columns}") if not target_columns or not economic_features: raise RuntimeError("학습에 쓸 숫자 칸이 없습니다.") # 예전: 빈 칸을 그대로 스케일러에 넣었다. # 지금: 남은 빈 칸은 앞뒤 날짜 값으로 채운 다음 스케일링한다. feature_columns = list(dict.fromkeys(target_columns + economic_features)) data[feature_columns] = data[feature_columns].apply( pd.to _numeric, errors='coerce').ffill().bfill() print("Scaling data...") train_size = int(len(data) * 0.8) train_data = data.iloc[:train_size] test_data = data.iloc[train_size:] data_scaled = data.copy() stock_scaler = MinMaxScaler() econ_scaler = MinMaxScaler() data_scaled[target_columns] = stock_ scaler.fit _transform(data[target_columns]) data_scaled[economic_features] = econ_ scaler.fit _transform(data[economic_features]) model = build_transformer_with_two_inputs(stock_shape, econ_shape, num_heads=8, ff_dim=256, target_size=len(target_columns)) # 예전: Adam(learning_rate=0.0001) # 지금: clipnorm=1.0 을 넣어 학습 중 숫자가 한없이 커지지 않게 했다. model.compile(optimizer=Adam(learning_rate=0.0001, clipnorm=1.0), loss='mse', metrics=['mae']) predicted_prices = model.predict([X_stock_full, X_econ_full], verbose=1) predicted_prices_actual = stock_scaler.inverse_transform(predicted_prices) # 예전: 예측하자마자 표로 만들고 저장했다. # 지금: 빈 칸 개수를 세고, 가격으로 되돌린 값이 전부 비어 있으면 저장하지 않고 멈춘다. raw_empty = int((~np.isfinite(predicted_prices)).sum()) inv_empty = int((~np.isfinite(predicted_prices_actual)).sum()) last_loss = history.history['loss'][-1] print(f"모델 출력 빈 값: {raw_empty} / {predicted_prices.size}") print(f"가격으로 되돌린 빈 값: {inv_empty} / {predicted_prices_actual.size}") print(f"마지막 학습 손실: {last_loss}") if inv_empty == predicted_prices_actual.size: raise RuntimeError( "모델 예측이 전부 비어 있습니다. " f"모델 출력 빈 값 {raw_empty}/{predicted_prices.size}, " f"가격 변환 빈 값 {inv_empty}/{predicted_prices_actual.size}, " f"마지막 학습 손실 {last_loss}. 데이터베이스는 수정하지 않았습니다." ) def save_predictions_to_db(result_df): try: # 예전: records = result_ df.to _dict('records') # 지금: 숫자는 그대로 두고, 비어 있는 칸만 null 로 바꾼다. records = json.loads(result_ df.to _json(orient='records')) if not records: raise ValueError("저장할 예측 결과가 없습니다.") # 예전: 넣을 내용을 확인하기 전에 기존 행을 지웠다. # 지금: 넣을 내용이 생긴 뒤에만 기존 행을 지운다. supabase.table("predicted_stocks").delete().neq("id", 0).execute() chunk_size = 100 for i in range(0, len(records), chunk_size): chunk = records[i:i+chunk_size] response = supabase.table("predicted_stocks").insert(chunk).execute() # 예전: 저장 응답이 비어 있어도 넘어갔다. # 지금: 응답이 비어 있으면 실패로 처리한다. if not response.data : raise RuntimeError(f"예측 결과 저장 응답이 비어 있습니다. offset={i}") print(f"{len(records)}개의 예측 결과가 데이터베이스에 저장되었습니다.") # 예전: 성공인지 실패인지 돌려주지 않았다. # 지금: 성공이면 True 와 빈 이유를 돌려준다. return True, None except Exception as e: print(f"데이터베이스 저장 오류: {e}") # 지금: 실패하면 False 와 실패 이유를 돌려준다. return False, str(e) # 예전: save_predictions_to_db(result_data) # print("모든 예측 결과가 DB에 저장되었습니다.") # 지금: 저장이 실패하면 성공이라고 말하지 않고, 이유를 보여 준 뒤 멈춘다. predictions_saved, save_error = save_predictions_to_db(result_data) if not predictions_saved: raise RuntimeError(f"예측 결과를 데이터베이스에 저장하지 못했습니다. 원인: {save_error}") print("모든 예측 결과가 DB에 저장되었습니다.") def get_predictions_from_db(chunk_size=1000): try: count_response = supabase.table("predicted_stocks").select("id", count="exact").execute() # 예전: total_count = count_response.count # 지금: 개수가 없으면 0으로 본다. total_count = count_response.count or 0 print(f"predicted_stocks 테이블의 총 레코드 수: {total_count}") # 예전: 행이 0개여도 날짜 칸을 읽다가 오류가 났다. # 지금: 행이 0개면 날짜를 읽지 않고 None 을 돌려준다. if total_count == 0: print("predicted_stocks 테이블에 데이터가 없습니다.") return None all_data = [] for offset in range(0, total_count, chunk_size): response = ( supabase.table("predicted_stocks") .select("*") .order("날짜", desc=False) .limit(chunk_size) .offset(offset) .execute() ) # 예전: chunk_data = response.data # 지금: 응답이 비어 있으면 빈 목록으로 본다. chunk_data = response.data or [] all_data.extend(chunk_data) df = pd.DataFrame(all_data) # 예전: 날짜 칸이 없어도 df['날짜'] 를 읽었다. # 지금: 표가 비었거나 날짜 칸이 없으면 None 을 돌려준다. if df.empty or '날짜' not in df.columns: print("가져온 데이터에 '날짜' 컬럼이 없습니다.") return None df['날짜'] = pd.to _datetime(df['날짜']) return df except Exception as e: print(f"데이터 가져오기 오류: {e}") return None # 예전: # data = get_predictions_from_db(chunk_size=1000) # if data is None or len(data) == 0: # print("데이터를 가져오는데 실패했습니다.") # exit(1) # target_columns = ['애플', '마이크로소프트', ...] # 지금: 데이터베이스를 다시 읽지 않고, 방금 만든 예측표를 그대로 평가한다. # 종목 목록도 다시 적지 않고, 위에서 걸러 둔 target_columns 를 쓴다. data = result_data.copy() data['날짜'] = pd.to _datetime(data['날짜']) forecast_horizon = 14 evaluation_results = evaluate_predictions(data, target_columns, forecast_horizon) rise_results = analyze_rise_predictions(data, target_columns) # 예전: 비교할 예측이 없어도 바로 두 표를 합쳤다. # 지금: 평가 결과가 비어 있으면 합치지 않고 멈춘다. if evaluation_results.empty or 'Stock' not in evaluation_results.columns: raise RuntimeError("평가할 예측값이 없습니다. 실제 가격과 예측값을 합치지 않습니다.") final_results = pd.merge(evaluation_results, rise_results, on='Stock', how='outer') 이런식으로 바꾸었어요 AI가
모든 예측 결과가 DB에 저장되었습니다. predicted_stocks 테이블의 총 레코드 수: 0 총 0개 데이터를 성공적으로 가져왔습니다! 데이터 가져오기 오류: '날짜' 데이터를 가져오는데 실패했습니다. --------------------------------------------------------------------------- AttributeError Traceback (most recent call last) /tmp/ipykernel_921/1990775403.py in <cell line: 0>() 520 521 # 3) Evaluate predictions --> 522 evaluation_results = evaluate_predictions(data, target_columns, forecast_horizon) 523 print("============ Evaluation Results ============") 524 print(evaluation_results) /tmp/ipykernel_921/1990775403.py in evaluate_predictions(data, target_columns, forecast_horizon) 382 383 # Check if the columns exist --> 384 if predicted_col not in data.columns or actual_col not in data.columns: 385 print(f"Skipping {col}: Columns not found in data ({predicted_col}, {actual_col})") 386 continue AttributeError: 'NoneType' object has no attribute 'columns' supabase api 키 입력해서 경제지표랑 주가를 supase에 자동으로 저장하는것까지 됐는데. ai 예측모델 하니까 저런식으로 나오네요..
강의를 수강하시다가 막히는 부분이 있는 경우는 "자주 묻는 질문"을 먼저 참고 부탁드립니다. 막히는 부분에 대해서 질문을 주실 때에는 꼭 강의 제목과 타임라인도 같이 작성 부탁드립니다. 베개 투자법: 자면서 돈 버는 AI 주식 자동 매매 머신 python fastapi 부분을 듣고 있습니다. 화면 아래를 보면, 기본 강의 자료와 강의 자료 2개가 항상 올라와있는데, 이 두 개는 같은 것이 강의 내내 올라오는 것인지가 궁금하고, 이 두 개를 어떻게 나눠서 사용해야 할 지 궁금합니다. 그리고, 각 해당 항목에 들어가면 예제 코드가 있나요? 나중에는 하나로 묶인 코드도 제공되는거지요?
안녕하세요. 강사님 강사님께서 26강 5일 가중이동평균 문제풀이 해주신 방법외에 아래와 같이 lag 함수 활용해서 문제 풀어도 현업에서 사용하기 문제 없을까요? with temp_01 as (select a.order_date as d_day, sum(b.amount) as sum_amount , row_number() over(order by date(a.order_date) asc) as rnum from nw.orders a join nw.order_items b on a.order_id = b.order_id where a.order_date >= date('1996-07-08') group by a.order_date) , temp_02 as ( select * , count(*) over(order by d_day rows between 4 preceding and current row) as cnt , avg(sum_amount) over(order by d_day rows between 4 preceding and current row) as m_avg_5days #일반 이동평균 구하기 , ( lag(sum_amount,1) over(order by d_day) * 1 + lag(sum_amount,2) over(order by d_day) * 1 + lag(sum_amount,3) over(order by d_day) * 1 + lag(sum_amount,4) over(order by d_day) * 0.5 + sum_amount * 1.5 ) / 5 as w_m_avg_5days #5일 가중이동평균 구하기 from temp_01 order by d_day ) select * from temp_02 where rnum >= 5; 이런식으로 풀어도 괜찮을까요? 현업에서 활용할때 어떤 방식이 더 효율적일지 궁금합니다!
안녕하세요! product_id를 집계 기준으로 하는 GROUP BY 구문을 작성할 때, 해당 product_id와 맵핑되는 category_id은 SELECT절에서 max(category_id)으로 처리하는 방식으로 설명해주셨습니다. 혹시 아래처럼 category_id도 GROUP BY에 같이 작성한다면, 어떤 점이 다르며 이슈나 문제가 될만한 상황이 있는지 궁금합니다! SELECT a.PRODUCT_ID, b.CATEGORY_ID, sum(amount) AS sum_by_prod FROM nw.ORDER_ITEMS a JOIN nw.PRODUCTS b ON a.PRODUCT_ID = b.PRODUCT_ID GROUP BY a.PRODUCT_ID, b.CATEGORY_ID
안녕하세요 선생님, 좋은 강의 잘 수강하고 있습니다. 다름이 아니라 실습 환경 세팅 중에 막히는 부분이 있어서 문의를 남기게 되었습니다. 제가 현재 개인 PC가 아닌 회사 노트북을 사용하여 실습을 진행하려다 보니, 사내 보안 및 권한 문제로 인해 로컬에 PostgreSQL을 설치할 수가 없는 상황입니다. 현재 DBeaver를 통해 사내 시스템인 Hive DB에만 접근이 가능 합니다. 제공해 주신 실습 파일( data_schema.backup )을 확인해 보았는데, 해당 파일은 PostgreSQL 전용 백업 파일이라서 제가 사용하는 Hive 환경에서는 복원(Restore)을 하거나 데이터를 읽어 들일 수가 없습니다. 강의를 계속 따라가고 싶은데, 혹시 이 백업 파일 대신 아래 두 가지 형태의 파일을 별도로 제공해 주실 수 있으실까요? 로우 데이터 파일: 엑셀이나 텍스트 형태의 원본 데이터 파일 (예: .csv 또는 .txt ) 스키마 쿼리 파일: 각 테이블의 컬럼명과 데이터 타입을 알 수 있는 테이블 생성 스크립트 (예: CREATE TABLE 문이 적힌 .sql 또는 텍스트 파일) CSV 파일과 테이블 생성 쿼리만 제공해 주시면, 제가 Hive 문법에 맞게 데이터 타입(예: VARCHAR -> STRING 등)을 직접 수정하여 테이블을 생성한 뒤 DBeaver의 데이터 Import 기능으로 밀어 넣어서 실습을 진행해 보겠습니다. 환경이 달라 번거로운 요청을 드리게 되어 죄송합니다. 확인해 주시면 정말 감사하겠습니다!
섹션1-11에서 MTputty를 다운로드하는 시간이였습니다. 사이트를 들어갔는데 현재 강의에서 사용되는 다운로드 URL은 사라져서 해당 홈페이지에서 다운로드 중이였는데, 다운로드 파일이 달라지고 링크 클릭 시 다른 페이지로 계속 이동되는 현상 때문에 의심스러워 AI에게 물어봐서 다운로드를 받았습니다. 결론적으로 공식 배포처는 ttyplus.com 이며 mtputty.com은 공식 사이트가 아닌 광고 수익형 사이트라 페이지 메타에 AdMaven광고 placement 삽입이 되어 있습니다. 처음에 다운로드 클릭 했을 때 VPN Download길레 뭐지 했습니다 AI 왈, 다운로드 링크는 제 3자의 GitHub 계정의 mtputty_auto_screen 저장 소스코드 ZIP으로 연결되어 있고 MTPutty는 프리웨어지만 오픈소스가 아니어서 소스 코드를 공개하지 않는 점으로 Git Hub에 공식 저장소가 존재할 수 없다 합니다. 그래서 공식 URL을 제공받아 다운로드를 진행 했는데 이점도 유의해서 사용하시면 될 것 같아요 https://ttyplus.com/download/mtputty_setup.exe
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 현재 Window 환경에 Ubuntu 20.04.6 이미지를 사용하고 Virtual Box 7버전을 사용하는데 터미널이 실행되지 않는 문제점이 발생합니다. 이에 따라 웹 서핑을 통해 Lang에 en 값을 uft8 값으로 변경해도 문제가 반복되어 서버를 삭제하고 다시 실행했는데 같은 문제가 반복되어 해당 강의에서 가상 머신 Virtual Box가 아닌 VMware로 사용해도 문제가 없나 질문드립니다.
안녕하세요 선생님. 강의 잘 듣고 있습니다. 강의( 06:39 )에서 설명하시는 mysql connection 정보 주석이 원본 소스 코드에는 누락된 것 같아서 제보 남깁니다. 다른 분들도 혼란 없으시길 바랍니다. extra field: { "charset": "utf8mb4", "local_infile": true } 감사합니다.
강사님 안녕하세요 강의를 듣다보니 인덱스를 어느정도 아는 사람이 들어야 이해도가 많이 높아질거 같아 문의 드립니다 혹시 강사님 강의 중 인덱스나 좀 더 기본기 모델링을 배울 수 있는 강의가 있을까요? (ex: Hash Table과 Tree 자료구조,인덱스) 또, 혹시 행 기반 dbms가 아닌 duck db , 빅쿼리등 열 기반 dbms 강의도 론칭 예정이 있으신지 궁금합니다 현재 빅쿼리를 사용중인 신입 데이터 엔지니어인데 인덱스 개념은 안쓰고 파티셔닝, 클러스터링 밖에 없더라구요..
섹션 1,3,4 등은 다운로드 할 수 있는 자료가 존재하는데, 섹션 2,6,7 등은 공유되어 있는 자료가 없는 걸로 보입니다. 해당 강의 자료는 일부러 공유가 안 되고 있는 상황인가요? 아니면 다른 곳에서 찾을 수 있나요? (자료가 공유된다면 보다 원활하게 들을 수 있을 것 같습니다.)