Skip to content

πŸ† 데이터 μ‚¬μ΄μ–ΈμŠ€ νŽ˜μŠ€ν‹°λ²Œ κ²½μ§„λŒ€νšŒ λŒ€μƒπŸ†

Notifications You must be signed in to change notification settings

ohilikeit/Data_Science_Festival_2022

Repository files navigation

데이터 μ‚¬μ΄μ–ΈμŠ€ νŽ˜μŠ€ν‹°λ²Œ κ²½μ§„λŒ€νšŒ

  • 주제 : 24μ‹œ 응급체계λ₯Ό μœ„ν•œ μ‹€μ™Έ AED 졜적 μœ„μΉ˜ μ„ μ •
  • κΈ°κ°„ : 2022.11. ~ 2022.12
  • μ΅œμ’… μˆœμœ„ : 1 st (50 teams)
  • κ΄€λ ¨ κΈ€ : λΈ”λ‘œκ·Έ

λ³€κ²½ 사항

  • 2023.08.05 : μ½”λ“œ refactoring
  • 2023.08.31 : λΈ”λ‘œκ·Έ 링크 μΆ”κ°€

Introduction

  • ν˜„μž¬ AEDλŠ” 곡곡기관과 μ§€ν•˜μ² μ— λ°€μ§‘λ˜μ–΄ ν‡΄κ·Όμ‹œκ°„ λŒ€ 이후 λŒ€λΆ€λΆ„ μ‚¬μš© λΆˆκ°€ν•¨
  • 이에 λ™λŒ€λ¬Έκ΅¬λ₯Ό κΈ°μ€€μœΌλ‘œ λŒ€λΆ€λΆ„μ˜ μ§€μ—­μ—μ„œ 24μ‹œ λ‚΄λ‚΄ AEDλ₯Ό μ‚¬μš©ν•  수 있게 μ‹€μ™Έ 슀마트 AEDλ₯Ό μ„€μΉ˜ν•˜κ³ μž 함

Preprocess & Model

0. polygon data

AED μœ νš¨λ³Œμœ„(200m) μ‹œκ°ν™”, μˆ˜μš”λŸ‰ 계산 및 λͺ¨λΈλ§μ„ μœ„ν•˜μ—¬ 200 buffer, 100 bufferλ₯Ό 생성

  • Example code:
# geodata λ³€κ²½ buffer 생성 - κΈ°μ‘΄ 24μ‹œκ°„ 가동 AEDμ™€μ˜ 유효거리 기반 μˆ˜μš”λŸ‰ b(buffer_100)
gs = gpd.GeoSeries.from_wkt(df['λ…Έλ“œ WKT'])
df_dobo_100 = gpd.GeoDataFrame(df, geometry = gs, crs = 'epsg:4326')

df_dobo_100 = df_dobo_100.set_geometry('geometry')
df_dobo_100['buffer_100'] = df_dobo_100.to_crs('epsg:5179').buffer(100).to_crs('epsg:4326')
df_dobo_100 = df_dobo_100.set_geometry('buffer_100')
df_dobo_100['buffer_100_coordinates'] = df_dobo_100['buffer_100'].apply(polygon_to_coordinates)

1. MCLP(Maximal Covering Location Problem)

μ‹œμ„€λ¬Όμ˜ 개수 ν˜Ήμ€ μ˜ˆμ‚° λΉ„μš©μ΄ μ œν•œλ˜μ—ˆμ„Β λ•Œ, μ‹œμ„€λ¬Όμ˜ μ„œλΉ„μŠ€ μˆ˜μ€€μ„ 높이기 μœ„ν•˜μ—¬ 주어진 μ œμ•½μ‘°κ±΄ ν•˜μ—μ„œ μ‹œμ„€λ¬Όμ΄ μ»€λ²„ν•˜λŠ” μˆ˜μš”λŸ‰μ„ μ΅œλŒ€ν™”ν•˜λŠ” μœ„μΉ˜λ₯Ό μ„ μ •ν•˜λŠ” 방법

2. λͺ¨λΈ κ°€μ •

  1. μˆ˜μš”μ§€μ™€ ν›„λ³΄μ§€λŠ” 동일
  2. AED μœ νš¨κ±°λ¦¬λŠ” 200m
  3. 도보 λ…Έλ“œ-링크 데이터λ₯Ό ν›„λ³΄μ§€λ‘œ ν™œμš©

4. μ΅œμ’… μˆ˜μš”λŸ‰(W) = 0.4 * a + 0.3 * b + 0.3 * c

3. 행정동 별 심정지 κ°€λŠ₯인ꡬ μΆ”μ •λŸ‰(μˆ˜μš”λŸ‰ a)

동별, 성별, λ‚˜μ΄λŒ€λ³„ 인ꡬ데이터에 ν•΄λ‹Ή ꡬ간 별 심정지 λ°œμƒλŸ‰μ„ κ³±ν•œ weighted sum

pop = pd.read_csv('./λ™λŒ€λ¬Έκ΅¬_동별_μ—°λ ΉλŒ€λ³„_인ꡬ수.csv')
cols = pop.columns
pop['male'] = pop[cols[2]] * 0.01 + pop[cols[3]] * 0.026 + pop[cols[4]] * 0.039 + pop[cols[5]] * 0.075 + pop[cols[6]] * 0.139 + pop[cols[7]] * 0.7
pop['male'] = pop['male'] / pop['male'].max()
pop['female'] = pop[cols[8]] * 0.01 + pop[cols[9]] * 0.026 + pop[cols[10]] * 0.039 + pop[cols[11]] * 0.075 + pop[cols[12]] * 0.139 + pop[cols[13]] * 0.7
pop['female'] = pop['female'] / pop['female'].max()
pop['a'] = 0.64 * pop['male'] + 0.36 * pop['female']

4. 반경 200m 이내 κΈ°μ‘΄ 24μ‹œκ°„ AED κ°œμˆ˜μ™€ κ²ΉμΉ˜λŠ” 정도(μˆ˜μš”λŸ‰ b, c)

주변에 κΈ°μ‘΄ 24μ‹œκ°„ 가동 AEDκ°€ λͺ‡κ°œ 있고 μ–Όλ§ˆλ‚˜ κ°€κΉκ²Œ μžˆλŠ”κ°€

total = pd.DataFrame()
for i in tqdm(df_dobo_100.index):
    db = df_dobo_100.loc[i, 'buffer_100']
    num = []
    area = []
    for j in aed_24_100.index:
        aed = aed_24_100.loc[j, "buffer_100"]
        num.append(db.intersects(aed))
        if db.intersects(aed) == True:
            area.append(db.intersection(aed).area)
    info = {"intersects_num" : sum(num), "intersects_area" : sum(area)}
    total = total.append(info, ignore_index=True)

# μ •κ·œν™” 및 μ΅œμ’… μˆ˜μš”λŸ‰ μ‚°μΆœ 
total['intersects_num_scaled'] = (total['intersects_num'].max() - total['intersects_num']) / total['intersects_num'].max()
total['intersects_area_scaled'] = (total['intersects_area'].max() - total['intersects_area']) / total['intersects_area'].max()

df_dobo_200['b'] = total['intersects_num_scaled'].values
df_dobo_200['c'] = total['intersects_area_scaled'].values
df_dobo_200['w'] = 0.4 * df_dobo_200['a'] + 0.3 * df_dobo_200['b'] + 0.3 * df_dobo_200['c']

5. MCLP modeling

mlp(mixed integer programming)을 ν†΅ν•œ μ΅œμ ν™”

temp = df_dobo_200.copy()

temp['λ…Έλ“œ ID'] = pd.to_numeric(temp['λ…Έλ“œ ID'])
temp['w'].index = temp['λ…Έλ“œ ID']
w = temp['w']
model = Model()
model.max_gap = 0.0
x = [model.add_var(name = "x%d" % i, var_type = BINARY) for i in temp['λ…Έλ“œ ID']]           # μ œμ•½ 쑰건 3 : ν¬μΈνŠΈμ— μ„€μΉ˜λ˜λŠ”κ°€
y = [model.add_var(name = "y%d" % i, var_type = BINARY) for i in temp['λ…Έλ“œ ID']]           # μ œμ•½ 쑰건 4 : ν¬μΈνŠΈκ°€ μ»€λ²„λ˜λŠ”κ°€
model.objective = maximize(xsum(w[i] * model.vars['y%d' %i] for i in temp['λ…Έλ“œ ID']))      # λͺ©μ ν•¨μˆ˜
model += xsum(model.vars['x%d' %j] for j in temp['λ…Έλ“œ ID']) == 40                          # μ œμ•½ 쑰건 2 : μ„€μΉ˜ν•  AED 개수

for num, idx in enumerate(temp['λ…Έλ“œ ID']):
    model += xsum(model.vars['x%d' %j] for j in cond_list[num]) >= model.vars['y%d' %idx]   # μ œμ•½ 쑰건 1 : cond_list(집합 N)에 μ†ν•œ 후보지 쀑 적어도 ν•œ 곳에 AEDκ°€ μž…μ§€ν•˜λ©΄ iλŠ” 컀버됨 
model.optimize()
solution = []
for j in temp['λ…Έλ“œ ID']:
    if model.vars['x%d' %j].x == 0:
        solution.append(0)
    else:
        solution.append(1)
temp['sol'] = solution
sol = temp[temp['sol'] == 1]

Conclusions

1. μΆ”κ°€ AED κ°œμˆ˜μ— λ”°λ₯Έ 컀버리지 λ³€ν™”

μΆ”κ°€ AED 개수 증가에 따라 컀버리지 μ¦κ°€μœ¨μ΄ 체감, 합리적인 개수 섀정이 ν•„μš”

2. μ΅œμ’… 후보지 μ„ μ •

  • μ΅œμ’…μ μœΌλ‘œ 40개의 μΆ”κ°€ AED μ„€μΉ˜, 전체 μ•½ 81% 컀버
  • 보라색 : κΈ°μ‘΄ 24μ‹œκ°„ AED
  • λ…Έλž€μƒ‰ : μƒˆλ‘œ μΆ”κ°€λœ μ‹€μ™Έ AED

Requirements

  • geopandas
  • pydeck
  • mip
  • pandas
  • shapely

About

πŸ† 데이터 μ‚¬μ΄μ–ΈμŠ€ νŽ˜μŠ€ν‹°λ²Œ κ²½μ§„λŒ€νšŒ λŒ€μƒπŸ†

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published