Database 분석 (4)

오늘은 데이터베이스 프로젝트를 진행했다. 


문제는 다음과 같았다.


# 📝 문제 리스트

아래 문제 중 **4개 이상 (필수 1개 + 선택 3개 이상)** 을 선택하여 수행합니다.  



## [필수] 1) 고심박(high HR) 위험군 탐지

- 일정 기준(예: heart_rate > 150)을 넘는 순간을 찾아서

  - 발생 시각  

  - 해당 활동  

  - 발생 빈도를 분석한다.


## 2) 활동(activity)별 평균 생체지표 분석

- 활동별로 heart_rate, step_count, resp_rate, body_temp의 평균을 계산하고 비교한다.

- 어떤 활동이 가장 높은 생체 지표를 보이는지 분석한다.


## 3) 체온 이상치(high fever) 탐지

- body_temp ≥ 38.0°C인 구간을 찾아  

  - 어떤 활동에서 많이 나타나는지  

  - 위험 패턴이 존재하는지 분석한다.


## 4) 산소포화도(SpO₂) 저하 위험 탐지

- blood_oxygen < 94% 데이터를 필터링하여  

  - 발생 시각  

  - activity를 분석한다.


## 5) 활동별 활동량(step_count) 분석

- 활동별로 step_count 합계와 평균을 구하고  

- 가장 활동량이 많은 활동을 찾는다.


## 6) 센서 오류(is_tampered) 데이터 탐지

- is_tampered = 1 이 발생한 횟수를 파악하고  

- 오류가 어떤 활동에서 많이 발생하는지 분석한다.


## 7) 시간대별 생체지표 분석

- 시간(HOUR) 기준으로 데이터를 그룹화하여  

  - 시간대별 평균 heart_rate  

  - 시간대별 평균 body_temp 패턴을 분석한다.


## 8) 특정 활동(Rest vs Walking 등) 비교 분석

- 두 활동을 선택하여 생체 지표 평균을 비교하고  

- 활동의 강도를 해석한다.


## 9) 복합 위험군 탐지

- 두 개 이상의 위험 조건을 동시에 만족하는 구간을 찾아 분석한다.  

  예: high heart rate + high temperature 조합.


## 10) 이상치 제거 전후 비교

- 센서 오류가 있는 데이터를 제거하기 전/후의 평균 생체 지표를 비교하여  

- 이상치 제거의 영향을 분석한다.


프로젝트를 통해 분석이 이루어졌고 기계어를 배운 것을 활용하는 것을 요구했으나 아래와 같은 지식이 필요해야 자료와 조건을 맞춰야 정확하게 분석할 수 있는 것이었다.


심장이 ‘쿵쾅’ 거리는 느낌이 들고, 맥박을 재보니 150 이상 특별한 이유 없이 지속된다면 부정맥이나 심장 질환의 신호

normal heart rate for an adult at rest is usually between 60 and 100 beats per minute

성인의 정상 심장 박동은 일반적으로 분당 60에서 100이다.

https://www.merckmanuals.com/home/heart-and-blood-vessel-disorders/abnormal-heart-rhythms/overview-of-abnormal-heart-rhythms?aiquery=what is normal heart rate

정상 체온은 36.1도에서 37.5도 사이

a fever to be a temperature of 100.4° F (approximately 38° C) or higher when measured rectally.

직장에서 체온을 측정했을 때 열은 섭씨 38도 혹은 그 이상이다.

https://www.merckmanuals.com/home/infections/biology-of-infectious-disease/fever-in-adults?aiquery=what is normal body temperature

95%에서 100% 사이

normal resting oxygen saturation of less than 95% is considered abnormal

산소 포화도가 95% 미만일 경우 비정상이다.

https://www.ncbi.nlm.nih.gov/books/NBK525974/

정상 호흡수는 성인 기준으로 분당 12~20회

During breathing at rest, the average adult inhales and exhales between 12 and 20 times a minute.

휴식 중에 성인의 정상 호흡은 분당 12회에서 20회이다. https://www.merckmanuals.com/home/lung-and-airway-disorders/biology-of-the-lungs-and-airways/control-of-breathing?aiquery=normal breathing frequency

분석한 자료는 생체지표라고 했으나 측정 내용을 따지고 보면 생물 측정[통계]이다. 생체지표는 ‘biomarker’으로 피 혹은 다른 조직에서 측정한 것을 지칭한다.

Biometrics is defined as the process of identifying individuals by detecting and recording their unique physical or behavioral traits using electronic devices, such as fingerprints, iris scans, or voice recognition.

https://www.sciencedirect.com/topics/computer-science/biometrics

Biomarkers are substances that can be measured in blood or other tissues to provide information about a person's health.

https://www.merckmanuals.com/home/aisearchresults?aiquery=what are biomarkers


분석한 것은 가짜 자료인 만큼 수치가 정상과는 거리가 있는 것이 나왔으나 위 조건에 알맞게 수준 있는 프로그래밍 언어를 사용해서 분석하기에는 어려움이 있었다.


print(f"--- 발생 빈도 (Frequency) ---")
print(f"심박수 150 초과 기록 총 횟수: {len(results_df)}회")

--- 발생 빈도 (Frequency) --- 심박수 150 초과 기록 총 횟수: 1179회


import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd

# Create a temporary filtered DataFrame for the plot
high_hr_df = df[df['heart_rate'] > 150].copy()

plt.figure(figsize=(10, 6))

# Use the new filtered DataFrame
sns.scatterplot(data=high_hr_df,
                x='timestamp',
                y='heart_rate',
                hue='activity', # Color by activity type
                s=100,
                alpha=0.7)

plt.title('Scatter Plot of Heart Rate (>150) Events')
plt.xlabel('Timestamp')
plt.ylabel('Heart Rate')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()



import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# 시각화 스타일 설정
sns.set_style("whitegrid")

# 사용할 데이터프레임 설정 (전체 df 사용 가정)
data_source = df

plt.figure(figsize=(10, 6))

# Seaborn barplot 사용 - estimator=max 설정
sns.barplot(data=data_source,
            x='activity',
            y='heart_rate',
            palette='plasma',      # 색상 팔레트 변경
            errorbar=None,
            estimator=max)         # ★ 이 부분을 max로 설정합니다

plt.title('Highest Heart Rate per Activity')
plt.xlabel('Activity Type')
plt.ylabel('Maximum Heart Rate')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()


import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# 시각화 스타일 설정
sns.set_style("whitegrid")

# 사용할 데이터프레임 설정 (전체 df 사용 가정)
data_source = df

plt.figure(figsize=(10, 6))

# Seaborn barplot 사용 - estimator=min 설정
# 일반적으로 휴식 중 심박수가 가장 낮으므로 낮은 값 범위를 확인하기 좋습니다.
sns.barplot(data=data_source,
            x='activity',
            y='heart_rate',
            palette='viridis',
            errorbar=None,
            estimator=min)         # ★ 이 부분을 min으로 설정합니다

plt.title('Lowest Heart Rate per Activity')
plt.xlabel('Activity Type')
plt.ylabel('Minimum Heart Rate')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()

plt.figure(figsize=(10, 6))

# seaborn의 histplot을 사용하면 자동으로 데이터를 구간(bins)으로 나누어 빈도를 계산합니다.
sns.histplot(data=df,
             x='heart_rate',
             bins=30,           # 데이터를 30개의 구간으로 나눕니다.
             kde=True,          # Kernel Density Estimation (밀도 곡선) 추가
             color='darkred')

plt.title('Histograph of Heart Rate')
plt.xlabel('Frequency')
plt.ylabel('Heart Rate BPM')
plt.show()
import pandas as pd
import numpy as np

Resting_data = df[df['activity'] == 'Resting']
Walking_data = df[df['activity']=='Walking']

avg_hr_resting = Resting_data['heart_rate'].mean()
avg_bt_resting = Resting_data['body_temp'].mean()
avg_bo_resting = Resting_data['blood_oxygen'].mean()
avg_rr_resting = Resting_data['resp_rate'].mean()

avg_hr_walking = Walking_data['heart_rate'].mean()
avg_bt_walking = Walking_data['body_temp'].mean()
avg_bo_walking = Walking_data['blood_oxygen'].mean()
avg_rr_walking = Walking_data['resp_rate'].mean()

# 1. 평균값들을 딕셔너리 형태로 묶습니다.
summary_data = {
    '평균 휴식(Resting)': [avg_hr_resting, avg_bt_resting, avg_bo_resting, avg_rr_resting],
    '평균 걷기(Walking)': [avg_hr_walking, avg_bt_walking, avg_bo_walking, avg_rr_walking]
}

# 2. 새로운 DataFrame을 생성하고 인덱스(행 이름)를 지정합니다.
summary_df = pd.DataFrame(summary_data, index=['심박수 (HR)', '체온 (Temp)', '혈중산소 (O2)', '호흡수 (RR)'])

# 3. 결과 요약 테이블을 출력합니다.
print("\n--- 활동별 평균 지표 요약 ---")
display(summary_df)

--- 활동별 평균 지표 요약 ---
평균 휴식(Resting)평균 걷기(Walking)
심박수 (HR)121.394143119.293828
체온 (Temp)37.58909037.534007
혈중산소 (O2)95.04122894.853357
호흡수 (RR)18.18092818.072406


# 테이블 'health_metrics'의 상위 5개 행 보기 (MySQL/PostgreSQL)
sql_2 = ''' SELECT * FROM df LIMIT 5 '''

# 만약 사용자가 원하는 대로 여러 테이블의 데이터를 조인해서 봐야 한다면:
sql_3 = ''' SELECT
    h.heart_rate,
    b.body_temp,
    b.blood_oxygen,
    r.resp_rate,
    a.activity
FROM
    heart_rate_table AS h '''

display(df.head(5))

timestampheart_rateblood_oxygenbody_tempresp_ratestep_countactivityaccel_xaccel_yaccel_zgyro_xgyro_ygyro_zis_tampered
02024-04-01 00:00:00163.090.90113636.31205213.0100Cycling-1.010299-0.313778-1.23737037.323647156.479698-245.7922280
12024-04-01 00:00:1060.097.70481537.72116819.07Resting1.485340-0.222970-0.013984-1.06307788.243246165.9103610
22024-04-01 00:00:20115.096.16816937.72876013.0171Walking-1.320600-0.910052-1.403447-240.402469235.152740-237.3140530
32024-04-01 00:00:30177.095.98637238.85671222.095Cycling1.406346-0.850460-0.920604-206.882084193.516981-188.8209690
42024-04-01 00:00:4063.092.92540437.32771219.0161Walking1.0913900.795830-0.069070-71.995709238.830512169.3345600


댓글

이 블로그의 인기 게시물

베이스 캠프에서 (1)

베이스 캠프에서 (2)