일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
- spacesyntax
- 서울
- 서울데이터
- 파이썬
- 베이지안
- naver
- Python
- 도시인공지능
- postgres
- 네이버
- 공간데이터
- QGIS
- SQL
- 도시설계
- 핫플레이스
- 웹크롤링
- multinomiallogitregression
- digital geography
- pandas
- 그래프색상
- connectivity
- platformurbanism
- 스마트시티
- 도시계획
- 공간분석
- digitalgeography
- 그래프이론
- 도시공간분석
- 베이지안뉴럴네트워크
- graphtheory
- Today
- Total
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
- spacesyntax
- 서울
- 서울데이터
- 파이썬
- 베이지안
- naver
- Python
- 도시인공지능
- postgres
- 네이버
- 공간데이터
- QGIS
- SQL
- 도시설계
- 핫플레이스
- 웹크롤링
- multinomiallogitregression
- digital geography
- pandas
- 그래프색상
- connectivity
- platformurbanism
- 스마트시티
- 도시계획
- 공간분석
- digitalgeography
- 그래프이론
- 도시공간분석
- 베이지안뉴럴네트워크
- graphtheory
- Today
- Total
이언배 연구노트
ADTP 찾아내기 본문
하... 내가 왜 ADTP를 붙일 수 있도록 nid 를 계속 추가하는 걸 까먹었을까...
문제:
내가 멍청하게 인허가데이터 기준으로 ndtp와 dtp 를 구분해두어서,
네이버 크롤링(naver place) 데이터베이스에 nid 로 지정해둔 adtp 데이터를
다시 인허가 데이터에서 찾는 멍청한 짓을 해야 한다는 사실이다.
그럼 ADTP를 추가하는 방법은 2가지가 있다.
1. 이성: 현재 DTP는 인허가 데이터 기준으로 분류가 되어있다. dtp를 구분하면서 했던 진행방식을 그대로 거치며, 인허가 데이터에 존재하는 내에서 adtp를 찾아낸다.
2. 본능: 네이버에 예약 링크 있으면 그게 장사 한다는 뜻 아님? 굳이 인허가 데이터를 왜 찾음?
하지만 나는 이성애자다.
일단 예약 가능 링크가 있는 음식점들의 pmid를 찾도록
"지금까지 했던 순서대로 다시 거슬러 올라가는" 짓을 해보자.
일단,
addr_match 단계에서
인허가 - 네이버 매칭 된 음식점들 중, 예약 링크가 있는 애들을 Materialized view 로 저장해두자.
CREATE MATERIALIZED VIEW adtp_byaddress AS
(WITH addr_match AS
(SELECT p.cls_main, p.pmid, p.title p_title, n.nid, n.title n_title,
similarity(p.title, n.title) AS text_sim,
ROW_NUMBER () OVER (PARTITION BY pmid ORDER BY similarity(p.title, n.title) DESC) AS pn_sim,
ROW_NUMBER () OVER (PARTITION BY nid ORDER BY similarity(p.title, n.title) DESC) AS np_sim
-- Partition 기능은 유용하다. 같은 pmid 내에서 정렬할 수 있도록 partition 별 구분을 가능케 해준다
FROM
(SELECT pmid, title, sig_nm, rd_nm, bd_bon, bd_bu, cls_main FROM permit_place) p
LEFT JOIN
(SELECT nid, title, sig_nm, rd_nm, bd_bon, bd_bu, cls_main FROM naver_place) n
ON
(p.cls_main = n.cls_main AND p.sig_nm = n.sig_nm AND p.rd_nm = n.rd_nm AND p.bd_bon = n.bd_bon AND p.bd_bu = n.bd_bu)
WHERE nid is not null), --NULL인 아이들은 일단, 같은 건물 내에 네이버 검색 결과가 없는 게다.;
-------------------------------------------1:1 매칭 성공
best_matched AS
(SELECT * FROM addr_match
WHERE pn_sim = 1 AND np_sim = 1 AND text_sim > 0.15 ORDER BY text_sim, pmid)
--------------------------------------------1:1 매칭 실패
SELECT b.pmid, b.p_title, ad.nid, ad.title n_title FROM best_matched b
JOIN (SELECT * FROM naver_place WHERE book LIKE 'h%') ad --예약 링크가 있는 애들을 중 매칭된 애들을 뽑는다.
ON b.nid = ad.nid);
총 21,473 개의 예약 가능 음식점들 중
17,043개의 음식점들은 한방에 매칭되었다.
이제 저 4,430개는 어디에...있는지..찾아야...한다...
일단 address로 걸러내지 못한 adtp 들을 따로 빼보자
SELECT ad_raw.* FROM adtp_byaddress ad
RIGHT JOIN
(SELECT * FROM naver_place WHERE book LIKE 'h%') ad_raw
ON ad.nid = ad_raw.nid
WHERE ad.nid IS NULL
아름답게 4430개, 딱 나머지 ADTP들이 나왔다.
얘들을 대상으로, geom query 를 다시 한 번 던져본다...
CREATE Materialized View ADTP_bygeom AS
(WITH
-----------------------------------------------주소로 매칭이 안된 ADTP들이다.
missed_adtp AS
(SELECT ad_raw.* FROM adtp_byaddress ad
RIGHT JOIN
(SELECT * FROM naver_place WHERE book LIKE 'h%') ad_raw
ON ad.nid = ad_raw.nid
WHERE ad.nid IS NULL),
--------------------------------------------인허가데이터에 geom 추가
unmatched_permit AS
(SELECT pmid, title, sig_nm, rd_nm, bd_bon, bd_bu, cls_main,
x, ST_Transform(ST_SetSRID(ST_MakePoint(x, y), 5174), 5179) geom ----------인허가데이터는 5174로 좌표를 제공한다.
FROM permit_place),
-------------------------------------------놓친 ADTP에 geom 추가
unmatched_naver AS
(SELECT nid, title, sig_nm, rd_nm, bd_bon, bd_bu, cls_main,
ST_Transform(geom, 5179) geom
FROM missed_adtp),
------------------------------------------포인트 좌표로 매칭
pointed_permit AS
(SELECT pmid, title, cls_main, sig_nm, rd_nm, geom
FROM unmatched_permit
WHERE x != 0 AND x is not null),
pointed_naver AS
(SELECT nid, title, cls_main, sig_nm, rd_nm, geom
FROM unmatched_naver),
----------------------------------------같은 도로명 주소를 가진 애들끼리 붙인다.
geom_joined AS
(SELECT pe.cls_main, pmid, pe.title p_title, nid, na.title n_title,
ST_Distance(pe.geom, na.geom) dist,
CASE
WHEN array_length(regexp_split_to_array(pe.title, '\s+'), 1) > 1 --띄어쓰기가 있으면
THEN
array_to_string(
ARRAY(
SELECT p_unset FROM
unnest(regexp_split_to_array(pe.title, '\s+')) AS p_unset
WHERE p_unset NOT LIKE '%점' AND array_length(regexp_split_to_array(pe.title, '\s+'), 1) > 1
), ' '
) -- '~~점' 으로 끝나는 단어를 제외하고 다시 텍스트를 구성한다
ELSE pe.title END AS p_onlytitle, -- 그렇지 않으면 그냥 원래 이름을 유지
CASE
WHEN array_length(regexp_split_to_array(na.title, '\s+'), 1) > 1
THEN
array_to_string(
ARRAY(
SELECT n_unset FROM
unnest(regexp_split_to_array(na.title, '\s+')) AS n_unset
WHERE n_unset NOT LIKE '%점' AND array_length(regexp_split_to_array(na.title, '\s+'), 1) > 1
), ' '
)
ELSE na.title END AS n_onlytitle
FROM (SELECT * FROM pointed_permit) pe
LEFT JOIN pointed_naver na
ON pe.sig_nm = na.sig_nm AND pe.rd_nm = na.rd_nm AND pe.cls_main = na.cls_main),
----------------------------------------text similarity 도 확dls
geom_match AS
(SELECT cls_main, pmid, p_title, p_onlytitle, nid, n_title, n_onlytitle, similarity(p_onlytitle, n_onlytitle) text_sim,
ROW_NUMBER () OVER (PARTITION BY pmid ORDER BY similarity(p_onlytitle, n_onlytitle) DESC) AS pn_sim,
ROW_NUMBER () OVER (PARTITION BY nid ORDER BY similarity(p_onlytitle, n_onlytitle) DESC) AS np_sim
FROM geom_joined WHERE dist < 100), -- 도로명 주소를 공유하는 애들 중 100m 이내
best_geom_matched AS
(SELECT *FROM geom_match
WHERE pn_sim = 1 AND np_sim = 1 AND text_sim > 0.2 ORDER BY text_sim, pmid)
--WHERE pn_sim = 1 AND np_sim = 1 AND text_sim > 0.5 ORDER BY text_sim, pmid)
SELECT * FROM best_geom_matched);
아아, 981개다. 솔직히 text sim 0.15 로 해도 되는데 진짜 한번 봐줬다.
나머지 애들 중에서 우리가 얻어낸 dtp_2024랑 매치될 수 있는 녀석들은 누구인가.
SELECT d.pmid, d.p_onlytitle, adtp_left.nid, adtp_left.n_onlytitle, similarity(d.p_onlytitle, adtp_left.n_onlytitle) sim FROM
(SELECT *, CASE
WHEN array_length(regexp_split_to_array(dtp_2024.title, '\s+'), 1) > 1 --띄어쓰기가 있으면
THEN
array_to_string(
ARRAY(
SELECT p_unset FROM
unnest(regexp_split_to_array(dtp_2024.title, '\s+')) AS p_unset
WHERE p_unset NOT LIKE '%점' AND array_length(regexp_split_to_array(dtp_2024.title, '\s+'), 1) > 1
), ' '
) -- '~~점' 으로 끝나는 단어를 제외하고 다시 텍스트를 구성한다
ELSE dtp_2024.title END AS p_onlytitle
FROM dtp_2024) d --우리는 dtp_2024 중에서 adtp들을 골라내는 과정 중에 있다.
LEFT JOIN
(SELECT ad_raw.*, CASE
WHEN array_length(regexp_split_to_array(ad_raw.title, '\s+'), 1) > 1
THEN
array_to_string(
ARRAY(
SELECT n_unset FROM
unnest(regexp_split_to_array(ad_raw.title, '\s+')) AS n_unset
WHERE n_unset NOT LIKE '%점' AND array_length(regexp_split_to_array(ad_raw.title, '\s+'), 1) > 1
), ' '
)
ELSE ad_raw.title END AS n_onlytitle
FROM adtp_byaddress ad
RIGHT JOIN
(SELECT np.* FROM
(SELECT * FROM naver_place WHERE book LIKE 'h%') np
LEFT JOIN adtp_bygeom adgeom
ON np.nid = adgeom.nid
WHERE adgeom.nid IS NULL) ad_raw -- NAVER Place 데이터에서 geom으로 붙은애 빼고
ON ad.nid = ad_raw.nid
WHERE ad.nid IS NULL) adtp_left --주소로 붙은 애들도 거르고, 나머지 adtp만 대상으로 본다
ON d.rd_nm = adtp_left.rd_nm AND
d.bd_bon = adtp_left.bd_bon AND d.bd_bu = adtp_left.bd_bu AND d.cls_main = adtp_left.cls_main --분류도 같고, 건물도 같은 애들끼리
WHERE similarity(d.p_onlytitle, adtp_left.n_onlytitle) >= 0.2 ORDER BY sim ASC --'점'을 떼고 이름으로 유사도 0.2 이상
코드가 괴랄해지는 이유는 저 '~~점'을 빼는 작업 때문이다 젠장.
122개 더 뺐다...
사실 0.2가 다소 애매하다고 느껴질 수 있긴 한데,
이렇게 해도 1082개밖에 안나오고, (3348개는 그냥 못찾은거다;;)
ADTP는 샘플 자체가 수가 적으니, 최대한 많이 뽑을 수 있는 대로 사용하는 것이 좋다.
SELECT pmid FROM adtp_byaddress byad
UNION
SELECT pmid FROM adtp_bygeom byg
UNION
SELECT pmid FROM adtp_bydtp byd;
이렇게 17512 개의 샘플을 확보했다...
솔직히 여기서 3000개 더 찾아야 한다는 얘기인데...
본능을 따르면 되겠지만, 그냥 정상적인 루트로 찾는 방법을 최대한 썼으니, 이대로 가자.
SELECT * FROm dtp_2024
JOIN
(SELECT pmid FROM adtp_byaddress byad
UNION
SELECT pmid FROM adtp_bygeom byg
UNION
SELECT pmid FROM adtp_bydtp byd) adtp
ON dtp_2024.pmid = adtp.pmid;
아마 adtp 의 pmid 에 중복이 있었을테니, 다소 숫자가 줄어드는 것도 이해가 간다.
그럼 이제 진짜 DTP에서 ADTP를 분리해내서, 새로운 materialized view를 만들어보자.
CREATE materialized view ADTP_2024 AS
(SELECT dtp_2024.* FROm dtp_2024
JOIN
(SELECT pmid FROM adtp_byaddress byad
UNION
SELECT pmid FROM adtp_bygeom byg
UNION
SELECT pmid FROM adtp_bydtp byd) adtp
ON dtp_2024.pmid = adtp.pmid);
CREATE MATERIALIZED VIEW dtp_2024_new AS
(SELECT d.* FROM dtp_2024 d
LEFT JOIN adtp_2024 ad
ON d.pmid = ad.pmid
WHERE ad.pmid IS NULL);
이렇게 해서 나의 새로운 데이터 셋 NDTP2024, DTP_2024, ADTP_2024가 완성되었다...
이제... 다시 분석 돌리러 가자...
'PostGRES' 카테고리의 다른 글
[PostGRES] DTP 데이터셋과 빌딩 데이터의 결합 (4) | 2024.12.04 |
---|---|
[PostGRES] DTP 데이터셋 완성하기 (1) | 2024.11.29 |
[PostGRES] 종로의 데이터에 geometry 를 심어보자. (0) | 2024.11.08 |
[PostGRES] NDTP-DTP 를 갈라내보자. (2) | 2024.11.07 |
[PostGRES] API 검색 결과를 데이터베이스로 비교 (1) | 2024.10.27 |