wanted-preonboarding-team-8 / pre-onboarding-9th-3-8 Goto Github PK
View Code? Open in Web Editor NEW원티드 프리온보딩 3차 과제
Home Page: https://pre-onboarding-9th-3-8.netlify.app
원티드 프리온보딩 3차 과제
Home Page: https://pre-onboarding-9th-3-8.netlify.app
key
값(시간)을 기반으로 시계열 차트를 만들어주세요value_area
값을 이용해주세요value_bar
값을 이용해주세요id, value_area, value_bar
데이터를 툴팁 형태로 제공해주세요아래 파일 내용을 함께 보면서 말씀 드리겠습니다.
No.1
함수의 파라미터 타입이 IChart[]
로 지정되었습니다.
타입스크립트의 타입 추론으로 리턴 타입 또한 동일합니다.
No.2
함수를 호출하면서 인자로 res.data.response
를 받습니다.
헌데 이 인자 값은 mock 데이터
가 그대로 넘어오는거라 No.1과 상충됩니다. (mock데이터의 형상이 IChart와는 다릅니다.)
No.3, No.4
No.1에서 말씀 드린 것 처럼 IChart[]
타입으로 리턴 된 값을 마찬가지로 타입 지정한 상태 값에 set
합니다.
[#4 ]
// 함수 파일 : lib/utils/transformData.ts
...
const transformData = (res: IChart[]) => { // No.1
for (const key in res) {
res[key].date = key;
}
return Object.values(res);
};
// 함수 사용 파일 : lib/hooks/useChart.ts
...
const useChart = () => {
const [charts, setCharts] = useState<IChart[]>([]); // No.4
const { start, end } = generateStartAndEndDate(charts);
useEffect(() => {
const getCharts = () => {
getData(API_URL)
.then((res) => transformData(res.data.response)) // No.2
.then(setCharts) // No.3
.catch(console.error);
};
getCharts();
}, []);
return { charts, start, end };
};
// 파일 : interface/chartData.d.ts
export interface IData {
id: string;
value_area: number;
value_bar: number;
}
export interface IChart extends IData { // type 확인
date: string;
}
// 파일 : api/chartData.ts
import apiClient from '@/api';
export const getData = (url: string) => { // 이 부분에 리턴 타입을 mock 데이터 형상과 똑같이 준다.
try {
return apiClient.get(url);
} catch (e) {
throw new Error('데이터가 없습니다.');
}
};
위처럼 타입을 지정 해 주고, 제한 된 타입 안에서 안전(?)하고 답답(?)하게 뒷부분도 맞춰서 과제를 진행하고 있습니다.
타입스크립트가 이것을 잡아내지 못했다는 것입니다.
물론 타입스크립트의 타입 시스템이 완벽하진 않다지만, 이 정도는 No.2
부분에서 잡혔어야 하는 거 아닌가요? 함수의 인자로 들어가는 값의 타입과, 함수의 파라미터에 입혀준 타입이 상충되니 말입니다.
한편 No.1
부분에서 파라미터의 타입으로 IChart[]
를 주셨기 때문에 해당 함수의 구문이 잘 동작합니다. 그렇지 않았다면 res[key].date = ...
처럼 무언가 할당 하려는 순간 에러: res에 그런 속성(date)은 없다
와 같은 에러가 나올 것입니다.
그래서 저는 어쩌면 정훈님이 이것을 의도하고 쓰셨을 수도 있다는 생각을 했습니다. 타입스크립트에는 이런저런 백도어가 많다고 하던데, 이 경우도 그렇지 않나 싶습니다.
목데이터 특성 파악을 중심으로
import warnings
warnings.filterwarnings(action='ignore')
import json, pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
plt.rcParams['font.family'] = 'Malgun Gothic'
from statsmodels.tsa.stattools import adfuller
from statsmodels.tsa.stattools import kpss
with open("public/mock/mockdata.json", encoding='utf-8') as f:
js = json.loads(f.read())
df = pd.DataFrame(js['response']).T
df.head()
id | value_area | value_bar | |
---|---|---|---|
2023-02-01 14:32:00 | 성북구 | 46 | 13111 |
2023-02-01 14:32:05 | 강남구 | 9 | 19143 |
2023-02-01 14:32:10 | 노원구 | 79 | 14798 |
2023-02-01 14:32:15 | 중랑구 | 4 | 14456 |
2023-02-01 14:32:20 | 노원구 | 97 | 19116 |
plt.figure(figsize=(40, 20))
plt.subplot(2, 2, 1)
plt.pie(df['id'].value_counts(), labels=df['id'].value_counts().index, autopct='%.1f%%')
plt.subplot(2, 2, 2)
plt.scatter(df['value_area'], df['value_bar'])
plt.subplot(2, 2, 3)
plt.plot(df['value_area'])
plt.xticks(rotation=90)
plt.subplot(2, 2, 4)
plt.plot(df['value_bar'])
plt.xticks(rotation=90)
plt.tight_layout()
plt.show()
id
의 경우, 성북구가 28%로 조금 더 많고 그 외는 동일하게 분포되어 있습니다.value_area
와 value_bar
는 특별한 관계를 가지지 않습니다.ADF 테스트와 KPSS 테스트를 모두 사용하여 시계열의 안정성에 대해 교차 확인할 것입니다.
ADF 테스트는 시계열이 안정적(Stationary)인지 여부를 확인하는데 이용되는 방법입니다.
def adf_test(values):
result = adfuller(values)
print('ADF Statistics: %f' % result[0])
print('p-value: %f' % result[1])
print('Critical values:')
for key, value in result[4].items():
print('\t%s: %.3f' % (key, value))
print('ADF Test: value_area')
adf_test(df['value_area'])
print('\nADF Test: value_bar')
adf_test(df['value_bar'])
ADF Test: value_area
ADF Statistics: -11.450498
p-value: 0.000000
Critical values:
1%: -3.498
5%: -2.891
10%: -2.583
ADF Test: value_bar
ADF Statistics: -5.163666
p-value: 0.000010
Critical values:
1%: -3.502
5%: -2.893
10%: -2.583
시계열이 평균 또는 선형 추세 주변에 고정되어 있는지 또는 단위 루트(unit root)로 인해 고정되지 않은지 확인합니다.
def kpss_test(values):
statistic, p_value, n_lags, critical_values = kpss(values)
print(f'KPSS Statistic: {statistic}')
print(f'p-value: {p_value}')
print(f'num lags: {n_lags}')
print('Critial Values:')
for key, value in critical_values.items():
print(f' {key} : {value}')
print('KPSS Test: value_area')
kpss_test(df['value_area'])
print('\nKPSS Test: value_bar')
kpss_test(df['value_bar'])
KPSS Test: value_area
KPSS Statistic: 0.06021346300418588
p-value: 0.1
num lags: 12
Critial Values:
10% : 0.347
5% : 0.463
2.5% : 0.574
1% : 0.739
KPSS Test: value_bar
KPSS Statistic: 0.22758849425522884
p-value: 0.1
num lags: 12
Critial Values:
10% : 0.347
5% : 0.463
2.5% : 0.574
1% : 0.739
현재 데이터는 여러 지역이 섞여 있습니다. 각 지역별로 구분하여도 안정적인지 확인합니다.
def adf_test_only_p_value(values):
result = adfuller(values)
print('ADF p-value: %f' % result[1])
def kpss_test_only_p_value(values):
statistic, p_value, n_lags, critical_values = kpss(values)
print(f'KPSS p-value: {p_value}')
for loc in df['id'].value_counts().index:
df_by_loc = df[df['id'] == loc]
print(f'\n{loc} Test:')
adf_test_only_p_value(df_by_loc['value_area'])
kpss_test_only_p_value(df_by_loc['value_area'])
성북구 Test:
ADF p-value: 0.007769
KPSS p-value: 0.1
강남구 Test:
ADF p-value: 0.065291
KPSS p-value: 0.1
노원구 Test:
ADF p-value: 0.000026
KPSS p-value: 0.09626532001173367
중랑구 Test:
ADF p-value: 0.000000
KPSS p-value: 0.08952778863900929
분석을 통해 파악한 특성은 아래와 같습니다.
id
의 경우, 성북구가 28%로 조금 더 많고 그 외는 동일하게 분포되어 있습니다.value_area
와 value_bar
는 특별한 관계를 가지지 않습니다.ifOverflow 'discard' | 'hidden' | 'visible' | 'extendDomain'
부분적으로 캔버스 밖에 있는 경우 참조 영역을 그리는 방법을 정의합니다. 'discard'로 설정하면 참조 영역이 전혀 그려지지 않습니다. '숨김'으로 설정하면 참조 영역이 캔버스에 잘립니다. 'visible'로 설정하면 참조 영역이 완전히 그려집니다. 'extendDomain'으로 설정하면 참조 영역이 캔버스에 맞도록 오버플로된 축의 도메인이 확장됩니다.
DEFAULT: 'discard'
https://recharts.org/en-US/api/ReferenceArea#ifOverflow
-ReferenceArea 의 ifOverflow 속성을 visible로 변경 후 정상화
PR 된 코드 받아서 약간 정리하다가 생각이 나서요. 지난주 세션이었나요? 멘토님께서 말씀하셨던 부분이기도 하고요.
저 개인적으로는 에디터 기능이 너무 좋아서 애초에 import 쪽을 쳐다 볼 일이 거의 없긴 합니다.
하지만 리뷰 할 때는 의미가 있는 것 같아요. 저희 팀원끼리는 공통 된 코드를 쓰니까 여전히 들여다 볼 일이 적지만, 처음 소스코드를 전달 받고 리뷰(평가)를 하는 입장에서는 가독성에 도움이 된다고 생각합니다.
제가 먼저 제안을 해 보자면,
import 라이브러리
import 리액트 내장 훅
import 커스텀 훅
import 컴포넌트
import 기타(유틸 함수 / 상수 /스타일 등등... )
import type
저 개인적으로 개발 순서에 따라 import 해 나가다 보면 대략 이렇게 쌓아지더라고요. 타입의 경우만 좀 쳐다볼 일이 생겨서 가장 빨리 볼 수 있는 곳에 두곤 했습니다.
한 가지만 더 제안 드려보자면 커스텀 훅을 export 할 때 default export 말고 그냥 export하는 건 별로일까요? 저는 커스텀 훅을 써 보는 것이 처음인데, import { useSomething } from ...
의 형태를 보면 훅이라는 걸 더 빨리 알 것 같다는 생각이 들어서요.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.