리트코드 : 197. Rising Temperature
문제
Table: Weather
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| id | int |
| recordDate | date |
| temperature | int |
+---------------+---------+
id is the column with unique values for this table.
There are no different rows with the same recordDate.
This table contains information about the temperature on a certain day.
Write a solution to find all dates' Id with higher temperatures compared to its previous dates (yesterday).
Return the result table in any order.
The result format is in the following example.
Example 1:
Input:
Weather table:
+----+------------+-------------+
| id | recordDate | temperature |
+----+------------+-------------+
| 1 | 2015-01-01 | 10 |
| 2 | 2015-01-02 | 25 |
| 3 | 2015-01-03 | 20 |
| 4 | 2015-01-04 | 30 |
+----+------------+-------------+
Output:
+----+
| id |
+----+
| 2 |
| 4 |
+----+
Explanation:
In 2015-01-02, the temperature was higher than the previous day (10 -> 25).
In 2015-01-04, the temperature was higher than the previous day (20 -> 30).
문제 풀이
MySQL
SELECT ID
FROM (
SELECT *,
DATEDIFF(RECORDDATE, LAG(RECORDDATE) OVER (ORDER BY RECORDDATE)) AS DATEDIFF,
TEMPERATURE - LAG(TEMPERATURE) OVER (ORDER BY RECORDDATE) AS DAYDIFF
FROM WEATHER
ORDER BY RECORDDATE
) AS TEMP
WHERE DATEDIFF = 1 AND DAYDIFF > 0
- LEAD, LAG처럼 이전, 이후 값을 가져오는 윈도우 함수를 사용해야한다.
- 서브쿼리 내 ORDER BY 절이 먼저 동작하므로 이전 값을 가져오면 전날인지 아닌지 판단 가능하다.
- 윈도우 절에 ORDER BY를 안넣는게 더 빠를 줄 알았는데 빼니까 더 느려짐.
- 풀면서 성능차이 더 확인해봐야할듯?
- LAG를 사용해서 이전 값을 가져온 테이블을 서브쿼리로 만든다.
- WHERE 조건으로 조건 맞게 불러와주면 끝.
Pandas
# SOLUTION 1
import pandas as pd
import datetime
def rising_temperature(weather: pd.DataFrame) -> pd.DataFrame:
weather.sort_values(by='recordDate',inplace=True)
weather['pre_temperature'] = weather['temperature'].shift(1)
weather['pre_recordDate'] = weather['recordDate'].shift(1)
result = weather[(weather['temperature'] > weather['pre_temperature']) &
((weather['recordDate'] - weather['pre_recordDate']) == timedelta(days=1))]
return result[['id']]
def rising_temperature(weather: pd.DataFrame) -> pd.DataFrame:
answer = []
if not weather.empty:
weather.sort_values(by='recordDate', inplace=True)
pre_T, pre_D = weather.iloc[0][['temperature', 'recordDate']]
for idx,row in weather.iloc[1:].iterrows():
T,D = row[['temperature', 'recordDate']]
if pre_T < T and D-pre_D == timedelta(days=1):
answer.append(row['id'])
pre_T, pre_D = T,D
return pd.DataFrame({'id':answer})
# SOLUTION 3
def rising_temperature(weather: pd.DataFrame) -> pd.DataFrame:
weather.sort_values(by="recordDate", inplace=True)
return weather[
(weather.temperature.diff() > 0) & (weather.recordDate.diff().dt.days == 1)
][["id"]]
- 날짜가 정렬되서 들어오지 않는 케이스가 존재하므로 날짜에 대해서 정렬해주기.
- SOLUTION 1
- shift 연산을 통해서 날짜랑 시간을 옮긴다.
- 전날 대비 기온 상승 & 날짜차이가 1일인 id를 반환한다.
- TABLE 자체가 DATE 객체라서 바로 연산이 가능하지만, 문자열로 들어있는 경우에는 컬럼에 to_datetime 연산을 해줘서 datetime으로 바꿔야한다.
- SOLUTION 2
- iterrow를 사용해서 풀이.
- 연산량이 많아서 데이터 프레임 크기가 크면 비효율적임.
- SOLUTION 3
- diff를 쓰면 shift를 사용해서 새로운 컬럼을 할당할 필요가 없다.
- diff에 정수를 쓰면 그 정수 인덱스 차이만큼 차이난 행에서 연산 진행
- 기본 인자로 diff(-1)이 들어가서 이전 row 정보를 바탕으로 연산한다.
코멘트
- LAG, LEAD, shift 등은 잘 안써서 시간 좀 걸린듯
'Data Analysis > Query' 카테고리의 다른 글
리트코드 : 570. Managers with at Least 5 Direct Reports (0) | 2024.04.09 |
---|---|
리트코드 : 550. Game Play Analysis IV (0) | 2024.04.08 |
리트코드 : 262. Trips and Users (0) | 2024.04.03 |
리트코드 : 183. Customers Who Never Order (0) | 2024.04.01 |
리트코드 : 182. Duplicate Emails (0) | 2024.03.31 |
리트코드 : 175. Combine Two Tables (0) | 2024.03.27 |
리트코드 : 181. Employees Earning More Than Their Managers (0) | 2024.03.27 |
댓글