1. pandas 개요
파이썬에서 데이터 처리를 위해 존재하는 가장 인기 있고 핵심적인 라이브러리
행과 열로 이루어진 2차원 데이터를 효율적으로 가공 및 처리 할 수 있는 다양한 기능 제공
numpy 기반, 훨씬 유연하고 편리하게 데이터 핸들링 가능
pandas의 핵심 객체는 여러개의 행과 열로 이루어진 2차원 데이터를 담는 데이터 구조체인 데이터 프레임
인덱스 : 관계형 데이터베이스 관리 시스템(RDBMS)의 기본키(PK)처럼 개별 데이터를 고유하게 식별하는 키
시리즈와 데이터 프레임은 모두 인덱스를 키로 가지고 있음
시리즈는 컬럼이 하나 뿐인 구조체, 데이터 프레임은 컬럼이 여러 개인 데이터 구조체
2. 시리즈(Series)와 데이터 프레임(DataFrame)
1) pandas 임포트
import pandas as pd #판다스 임포트
2) 시리즈
1차원의 배열 형태를 가진 자료구조
인덱스(Index)와 값(Value)으로 이루어짐
s=pd.Series([1,3,5,6,8])
print(s)
print(s.index)
print(s.values)
''' 결과
0 1
1 3
2 5
3 6
4 8
dtype: int64
RangeIndex(start=0, stop=5, step=1)
[1 3 5 6 8] '''
3) 데이터 프레임
2차원 행렬 구조의 테이블 형태
행 방향의 인덱스(Index)와 열 방향의 컬럼(Column)이 존재
v=[[1,2,3],[4,5,6],[7,8,9]]
i=['첫째행','둘째행','셋째행']
c=['컬럼1','컬럼2','컬럼3']
df=pd.DataFrame(v,index=i,columns=c)
print(df)
''' 결과
v=[[1,2,3],[4,5,6],[7,8,9]]
i=['첫째행','둘째행','셋째행']
c=['컬럼1','컬럼2','컬럼3']
df=pd.DataFrame(v,index=i,columns=c)
print(df) '''
3. 데이터 프레임 생성
1) 리스트로 생성
.DataFrame(리스트, column=['컬럼명1', '컬럼명2',' 컬럼명3'])
d=[
['100','강백호',9.7],
['101','송태섭',8.9],
['102','서태웅',9.3],
['103','채치수',6.1]
]
df=pd.DataFrame(d,columns=['번호','이름','점수'])
print(df)
''' 결과
번호 이름 점수
0 100 강백호 9.7
1 101 송태섭 8.9
2 102 서태웅 9.3
3 103 채치수 6.1 '''
2) 딕셔너리로 생성
.DataFrame(딕셔너리)
d={
'번호' : ['100','101','102','103'],
'이름' : ['강백호','송태섭','서태웅','채치수'],
'점수' : [9.7,8.9,9.3,6.1]
}
df=pd.DataFrame(d)
print(df)
''' 결과
번호 이름 점수
0 100 강백호 9.7
1 101 송태섭 8.9
2 102 서태웅 9.3
3 103 채치수 6.1 '''
3) csv 파일로 생성하기 .read_csv('파일경로', sep='\t') / sep 옵션 인자를 생략하면 자옹으로 콤마 할당
housing_df=pd.read_csv('/content/sample_data/california_housing_train.csv')
print('housing 변수 type : ',type(housing_df))
print(housing_df)
''' 결과
housing 변수 type : <class 'pandas.core.frame.DataFrame'>
longitude latitude housing_median_age total_rooms total_bedrooms \
0 -114.31 34.19 15.0 5612.0 1283.0
1 -114.47 34.40 19.0 7650.0 1901.0
2 -114.56 33.69 17.0 720.0 174.0
3 -114.57 33.64 14.0 1501.0 337.0
4 -114.57 33.57 20.0 1454.0 326.0
... ... ... ... ... ...
16995 -124.26 40.58 52.0 2217.0 394.0
16996 -124.27 40.69 36.0 2349.0 528.0
16997 -124.30 41.84 17.0 2677.0 531.0
16998 -124.30 41.80 19.0 2672.0 552.0
16999 -124.35 40.54 52.0 1820.0 300.0
population households median_income median_house_value
0 1015.0 472.0 1.4936 66900.0
1 1129.0 463.0 1.8200 80100.0
2 333.0 117.0 1.6509 85700.0
3 515.0 226.0 3.1917 73400.0
4 624.0 262.0 1.9250 65500.0
... ... ... ... ...
16995 907.0 369.0 2.3571 111400.0
16996 1194.0 465.0 2.5179 79000.0
16997 1244.0 456.0 3.0313 103600.0
16998 1298.0 478.0 1.9797 85800.0
16999 806.0 270.0 3.0147 94600.0
[17000 rows x 9 columns] '''
4. 데이터 프레임 훑어보기
1) 데이터 프레임 head 함수
.head(x) : 맨 앞에 있는 x개의 행 반환
.shape : 데이터 프레임의 행과 열 정보를 튜플 형태로 반환
print('DataFrame 크기 : ',housing_df.shape)
print(housing_df.head(5))
''' 결과
DataFrame 크기 : (17000, 9)
longitude latitude housing_median_age total_rooms total_bedrooms \
0 -114.31 34.19 15.0 5612.0 1283.0
1 -114.47 34.40 19.0 7650.0 1901.0
2 -114.56 33.69 17.0 720.0 174.0
3 -114.57 33.64 14.0 1501.0 337.0
4 -114.57 33.57 20.0 1454.0 326.0
population households median_income median_house_value
0 1015.0 472.0 1.4936 66900.0
1 1129.0 463.0 1.8200 80100.0
2 333.0 117.0 1.6509 85700.0
3 515.0 226.0 3.1917 73400.0
4 624.0 262.0 1.9250 65500.0 '''
2) 데이터 프레임 info, describe 함수
.info() : Non-Null 데이터 개수, 컬럼의 타입 조회
print(housing_df.info())
''' 결과
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 17000 entries, 0 to 16999
Data columns (total 9 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 longitude 17000 non-null float64
1 latitude 17000 non-null float64
2 housing_median_age 17000 non-null float64
3 total_rooms 17000 non-null float64
4 total_bedrooms 17000 non-null float64
5 population 17000 non-null float64
6 households 17000 non-null float64
7 median_income 17000 non-null float64
8 median_house_value 17000 non-null float64
dtypes: float64(9)
memory usage: 1.2 MB
None '''
.describe() : 숫자형 데이터의 개수, 평균값, 표준편차, 최솟값, 사분위 값, 최댓값 조회
print(housing_df.describe())
''' 결과
longitude latitude housing_median_age total_rooms \
count 17000.000000 17000.000000 17000.000000 17000.000000
mean -119.562108 35.625225 28.589353 2643.664412
std 2.005166 2.137340 12.586937 2179.947071
min -124.350000 32.540000 1.000000 2.000000
25% -121.790000 33.930000 18.000000 1462.000000
50% -118.490000 34.250000 29.000000 2127.000000
75% -118.000000 37.720000 37.000000 3151.250000
max -114.310000 41.950000 52.000000 37937.000000
total_bedrooms population households median_income \
count 17000.000000 17000.000000 17000.000000 17000.000000
mean 539.410824 1429.573941 501.221941 3.883578
std 421.499452 1147.852959 384.520841 1.908157
min 1.000000 3.000000 1.000000 0.499900
25% 297.000000 790.000000 282.000000 2.566375
50% 434.000000 1167.000000 409.000000 3.544600
75% 648.250000 1721.000000 605.250000 4.767000
max 6445.000000 35682.000000 6082.000000 15.000100
median_house_value
count 17000.000000
mean 207300.912353
std 115983.764387
min 14999.000000
25% 119400.000000
50% 180400.000000
75% 265000.000000
max 500001.000000 '''
3) 시리즈 head 함수
데이터 프레임의 [ ] 연산자 내부에 컬럼명을 입력하면 해당 컬럼에 해당하는 시리즈 객체 반환
housing_median_age=housing_df['housing_median_age']
print(housing_median_age.head(5))
''' 결과
0 15.0
1 19.0
2 17.0
3 14.0
4 20.0
Name: housing_median_age, dtype: float64 '''
4) 시리즈 value_count 함수
데이터의 분포도를 확인. 컬럼 값의 유형과 건수를 확인. 건수가 많은 순서로 정렬
value_counts=housing_median_age.value_counts()
''' 결과
52.0 1052
36.0 715
35.0 692
16.0 635
17.0 576
34.0 567
33.0 513
26.0 503
18.0 478
25.0 461
32.0 458
37.0 437
15.0 416
19.0 412
28.0 400
27.0 397
24.0 389
31.0 384
30.0 384
20.0 383
23.0 382
29.0 374
21.0 373
14.0 347
22.0 323
38.0 318
42.0 308
39.0 302
44.0 296
43.0 286
13.0 249
40.0 249
45.0 235
41.0 232
10.0 226
11.0 208
5.0 199
46.0 196
12.0 192
8.0 178
47.0 175
9.0 172
4.0 161
7.0 151
48.0 135
6.0 129
50.0 112
49.0 111
2.0 49
3.0 46
51.0 32
1.0 2
Name: housing_median_age, dtype: int64 '''
5. 데이터 프레임 컬럼 생성과 수정
1) 신규 컬럼 생성
[ ] 연산자 이용
housing_df['Age_0']=0
print(housing_df.head(3)) #Age_0 컬럼 추가, 0값 할당
''' 결과
longitude latitude housing_median_age total_rooms total_bedrooms \
0 -114.31 34.19 15.0 5612.0 1283.0
1 -114.47 34.40 19.0 7650.0 1901.0
2 -114.56 33.69 17.0 720.0 174.0
population households median_income median_house_value Age_0
0 1015.0 472.0 1.4936 66900.0 0
1 1129.0 463.0 1.8200 80100.0 0
2 333.0 117.0 1.6509 85700.0 0 '''
2) 신규 컬럼 생성 응용
housing_df['Age_by_10']=housing_df['housing_median_age']//10
print(housing_df.head(3)) #Age_by_10 컬럼 추가, age 컬럼시리즈를 10으로 나눴을 때의 몫 할당
''' 결과
longitude latitude housing_median_age total_rooms total_bedrooms \
0 -114.31 34.19 15.0 5612.0 1283.0
1 -114.47 34.40 19.0 7650.0 1901.0
2 -114.56 33.69 17.0 720.0 174.0
population households median_income median_house_value Age_0 Age_by_10
0 1015.0 472.0 1.4936 66900.0 0 1.0
1 1129.0 463.0 1.8200 80100.0 0 1.0
2 333.0 117.0 1.6509 85700.0 0 1.0 '''
3) 컬럼 데이터 수정
housing_df['Age_by_10']=housing_df['Age_by_10']*10 #Age_by_10 컬럼 값에 곱하기 10을 적용
''' 결과
longitude latitude housing_median_age total_rooms total_bedrooms \
0 -114.31 34.19 15.0 5612.0 1283.0
1 -114.47 34.40 19.0 7650.0 1901.0
2 -114.56 33.69 17.0 720.0 174.0
population households median_income median_house_value Age_0 Age_by_10
0 1015.0 472.0 1.4936 66900.0 0 10.0
1 1129.0 463.0 1.8200 80100.0 0 10.0
2 333.0 117.0 1.6509 85700.0 0 10.0 '''
4) 신규 컬럼 vlaue_counts 함수
value_counts=housing_df['Age_by_10'].value_counts() #연령대별 데이터 분포 확인
print(value_counts)
''' 결과
30.0 4770
20.0 3985
10.0 3739
40.0 2223
50.0 1196
0.0 1087
Name: Age_by_10, dtype: int64 '''
6. 데이터 프레임 데이터 삭제
1) 컬럼 데이터 삭제하기
.drop(labels, axix=0, index=None, columns=None, level=None, inplace=False, errors='raise') : 데이터 삭제
housing_drop_df=housing_df.drop('Age_0',axis=1) #axis=1 : 열 삭제 / 기본 inplace=False 원데이터 유지
print(housing_drop_df.head(3)) # Age_0 열 삭제, 원데이터는 그대로 유지
''' 결과
longitude latitude housing_median_age total_rooms total_bedrooms \
0 -114.31 34.19 15.0 5612.0 1283.0
1 -114.47 34.40 19.0 7650.0 1901.0
2 -114.56 33.69 17.0 720.0 174.0
population households median_income median_house_value Age_by_10
0 1015.0 472.0 1.4936 66900.0 10.0
1 1129.0 463.0 1.8200 80100.0 10.0
2 333.0 117.0 1.6509 85700.0 10.0 '''
2) 복수 컬럼 데이터 삭제하기
drop_result=housing_df.drop(['Age_0','Age_by_10'],axis=1,inplace=True)
print('drop_result 반환값 : ',drop_result) # Age_0, Age_by_10 열 원본 데이터 포함 삭제
print(housing_df.head(3))
''' 결과
drop_result 반환값 : None
longitude latitude housing_median_age total_rooms total_bedrooms \
0 -114.31 34.19 15.0 5612.0 1283.0
1 -114.47 34.40 19.0 7650.0 1901.0
2 -114.56 33.69 17.0 720.0 174.0
population households median_income median_house_value
0 1015.0 472.0 1.4936 66900.0
1 1129.0 463.0 1.8200 80100.0
2 333.0 117.0 1.6509 85700.0 '''
3) 행 데이터 삭제하기
housing_drop_df=housing_df.drop([0,1,2], axis=0) # 0,1,2 행 삭제
print(housing_drop_df.head(3))
''' 결과
longitude latitude housing_median_age total_rooms total_bedrooms \
3 -114.57 33.64 14.0 1501.0 337.0
4 -114.57 33.57 20.0 1454.0 326.0
5 -114.58 33.63 29.0 1387.0 236.0
population households median_income median_house_value
3 515.0 226.0 3.1917 73400.0
4 624.0 262.0 1.9250 65500.0
5 671.0 239.0 3.3438 74000.0 '''
7. 데이터 프레임 데이터 조회
1) 컬럼명으로 데이터 조회
numpy의 [ ] 연산자는 행의 위치, 열의 위치, 슬라이싱 범위 등을 지정해 데이터를 가져올 수 있다.
데이터 프레임의 [ ] 안에 들어갈 수 있는 것은 컬럼명 문자 또는 인덱스로 변환 가능한 표현식이다.
print('단일 컬럼 데이터 조회 :\n', housing_df['housing_median_age'].head(3)) #컬럼명 문자 지정 조회
print('\n복수 컬럼 데이터 조회 :\n', housing_df[['housing_median_age','total_rooms']].head(3))
''' 결과
단일 컬럼 데이터 조회 :
0 15.0
1 19.0
2 17.0
Name: housing_median_age, dtype: float64
복수 컬럼 데이터 조회 :
housing_median_age total_rooms
0 15.0 5612.0
1 19.0 7650.0
2 17.0 720.0 '''
2) 인덱스 슬라이싱으로 데이터 조회
print(housing_df[0:3])
''' 결과
longitude latitude housing_median_age total_rooms total_bedrooms \
0 -114.31 34.19 15.0 5612.0 1283.0
1 -114.47 34.40 19.0 7650.0 1901.0
2 -114.56 33.69 17.0 720.0 174.0
population households median_income median_house_value
0 1015.0 472.0 1.4936 66900.0
1 1129.0 463.0 1.8200 80100.0
2 333.0 117.0 1.6509 85700.0 '''
3) 논리형 인덱싱으로 데이터 조회
#housing_median_age 컬럼의 데이터 값이 30인 경우만 위에서 3개 추출
print(housing_df[housing_df['housing_median_age']==30].head(3))
''' 결과
longitude latitude housing_median_age total_rooms total_bedrooms \
26 -115.37 32.82 30.0 1602.0 322.0
50 -115.52 34.22 30.0 540.0 136.0
101 -115.59 32.69 30.0 935.0 177.0
population households median_income median_house_value
26 1130.0 335.0 3.5735 71100.0
50 122.0 63.0 1.3333 42500.0
101 649.0 148.0 2.5769 94400.0 '''
4) 복수 논리형 인덱싱으로 데이터 조회
#housing_median_age가 30초과, total_rooms가 100미만 median_income는 10초과인 데이터를 위에서 3개추출
print(housing_df[
(housing_df['housing_median_age']>30) &
(housing_df['total_rooms']<100) &
(housing_df['median_income']>10)
].head(3))
''' 결과
longitude latitude housing_median_age total_rooms total_bedrooms \
6030 -118.22 34.06 52.0 48.0 6.0
13055 -121.87 37.46 43.0 91.0 12.0
14501 -122.14 37.50 46.0 30.0 4.0
population households median_income median_house_value
6030 41.0 10.0 10.2264 112500.0
13055 58.0 16.0 15.0001 500001.0
14501 13.0 5.0 15.0001 500001.0 '''
5) 변수 논리형 인덱싱으로 데이터 조회
con1=housing_df['housing_median_age']>30 #housing_median_age 30 초과
con2=housing_df['total_rooms']<100 #total_rooms 100 미만
con3=housing_df['median_income']>10 #median_income 10 초과
print(housing_df[con1&con2&con3].head(3)) #위 세 조건을 만족하는 데이터 추출
''' 결과
longitude latitude housing_median_age total_rooms total_bedrooms \
6030 -118.22 34.06 52.0 48.0 6.0
13055 -121.87 37.46 43.0 91.0 12.0
14501 -122.14 37.50 46.0 30.0 4.0
population households median_income median_house_value
6030 41.0 10.0 10.2264 112500.0
13055 58.0 16.0 15.0001 500001.0
14501 13.0 5.0 15.0001 500001.0 '''
6) iloc 함수로 데이터 조회
.iloc[행, 열]
print(housing_df.iloc[0,2]) #행, 열으로 데이터 조회
''' 결과
15.0 '''
7) loc 함수로 데이터 조회
.loc[인덱스 값, 컬럼명]
print(housing_df.loc[0,'housing_median_age']) #인덱스, 컬럼명으로 데이터 조회
''' 결과
15.0 '''
8) loc 함수로 복수 데이터 조회
print(housing_df.loc[0:4,'housing_median_age']) #슬라이싱으로 복수 행 데이터 조회
''' 결과
0 15.0
1 19.0
2 17.0
3 14.0
4 20.0
Name: housing_median_age, dtype: float64 '''
9) loc 함수로 조건부 데이터 조회
#housing_median_age가 30인 housing_median_age, total_bedrooms 컬럼 위에서 3개출력
print(housing_df.loc[housing_df['housing_median_age']==30,['housing_median_age','total_bedrooms']].head(3))
''' 결과
housing_median_age total_bedrooms
26 30.0 322.0
50 30.0 136.0
101 30.0 177.0 '''
8. 데이터 프레임 데이터 정렬과 집계
1) 오름차순 정렬
.sort_values(by=['컬럼명'], ascending=True, inplace=False) : 정렬
ascending은 기본 True(오름차순), inplace은 기본 False(원본데이터 유지)
housing_sorted=housing_df.sort_values(by=['housing_median_age'])
print(housing_sorted.head(3)) #housing_median_age 오름차순 위에서 데이터 3개
''' 결과
longitude latitude housing_median_age total_rooms total_bedrooms \
13708 -122.00 38.23 1.0 2062.0 343.0
10993 -120.93 37.65 1.0 2254.0 328.0
1353 -117.17 34.12 2.0 3867.0 573.0
population households median_income median_house_value
13708 872.0 268.0 5.2636 191300.0
10993 402.0 112.0 4.2500 189200.0
1353 1275.0 433.0 5.4138 164400.0 '''
2) 복수 컬럼 내림차순 정렬
housing_sorted=housing_df.sort_values(by=['housing_median_age','total_rooms'], ascending=False)
print(housing_sorted.head(3)) #housing_median_age,total_rooms 순 내림차순 위에서 데이터 3개
''' 결과
longitude latitude housing_median_age total_rooms total_bedrooms \
15772 -122.41 37.79 52.0 6016.0 2509.0
15773 -122.41 37.79 52.0 5783.0 2747.0
11163 -121.03 40.35 52.0 5486.0 1044.0
population households median_income median_house_value
15772 3436.0 2119.0 2.5166 275000.0
15773 4518.0 2538.0 1.7240 225000.0
11163 1977.0 754.0 2.1833 49500.0 '''
3) 집계 함수 적용
sum() / count() = 평균
print(housing_df.sum()/housing_df.count())
''' 결과
longitude -119.562108
latitude 35.625225
housing_median_age 28.589353
total_rooms 2643.664412
total_bedrooms 539.410824
population 1429.573941
households 501.221941
median_income 3.883578
median_house_value 207300.912353
dtype: float64 '''
4) 특정 컬럼 함수 적용
print(housing_df[['housing_median_age','total_rooms']].mean()) #housing_median_age, total_rooms 평균
''' 결과
housing_median_age 28.589353
total_rooms 2643.664412
dtype: float64 '''
5) groupby 함수 적용
#housing_median_age를 대상으로 group지어져 평균 위에서 데이터 3개
housing_groupby=housing_df.groupby('housing_median_age').mean()
print(housing_groupby.head(3))
''' 결과
longitude latitude total_rooms total_bedrooms \
housing_median_age
1.0 -121.465000 37.940000 2158.000000 335.500000
2.0 -119.035306 35.410816 5237.102041 871.448980
3.0 -118.798478 35.164783 6920.326087 1190.826087
population households median_income \
housing_median_age
1.0 637.000000 190.000000 4.756800
2.0 2005.224490 707.122449 5.074237
3.0 2934.673913 1030.413043 5.572013
median_house_value
housing_median_age
1.0 190250.000000
2.0 229438.836735
3.0 239450.043478 '''
6) 특정 컬럼 groupby 함수 적용
#groupby된 데이터 중 특정 칼럼만 집계 적용
housing_groupby=housing_df.groupby('housing_median_age')[['total_rooms','total_bedrooms']].mean()
print(housing_groupby.head(3))
''' 결과
total_rooms total_bedrooms
housing_median_age
1.0 2158.000000 335.500000
2.0 5237.102041 871.448980
3.0 6920.326087 1190.826087 '''
7) 특정 컬럼 groupby, agg 함수 적용
#groupby를 통해 여러 개의 집계 함수를 호출하고자 할 때 agg 사용
housing_groupby=housing_df.groupby('housing_median_age')['total_rooms'].agg([min,max,sum])
print(housing_groupby.head(3))
''' 결과
min max sum
housing_median_age
1.0 2062.0 2254.0 4316.0
2.0 96.0 21897.0 256618.0
3.0 475.0 21060.0 318335.0 '''
9. 데이터 프레임 결측치 처리하기
1) 결측치 여부 확인 (Null)
.isna() : 결측치 여부 True, False로 출력
import numpy as np
housing_df['Age_na']=np.nan #Age_na 컬럼 생성, NaN값으로 초기화
print(housing_df.isna().head(3)) #isna() 결측치 여부 확인
''' 결과
longitude latitude housing_median_age total_rooms total_bedrooms \
0 False False False False False
1 False False False False False
2 False False False False False
population households median_income median_house_value Age_na
0 False False False False True
1 False False False False True
2 False False False False True '''
2) 결측치 개수 확인
sum() 함수 호출 시 결측치 True 는 1 False 는 0으로 변환되어 결측치의 개수를 구할 수 있다.
print(housing_df.isna().sum())
''' 결과
longitude 0
latitude 0
housing_median_age 0
total_rooms 0
total_bedrooms 0
population 0
households 0
median_income 0
median_house_value 0
Age_na 17000
dtype: int64 '''
3) 결측치 데이터 대체하기
.fillna() : 대체
#housing_df의 Age_na 컬럼을 housing_median_age 컬럼의 평균으로 대체
housing_df['Age_na']=housing_df['Age_na'].fillna(housing_df['housing_median_age'].mean())
print(housing_df.head(3))
''' 결과
longitude latitude housing_median_age total_rooms total_bedrooms \
0 -114.31 34.19 15.0 5612.0 1283.0
1 -114.47 34.40 19.0 7650.0 1901.0
2 -114.56 33.69 17.0 720.0 174.0
population households median_income median_house_value Age_na
0 1015.0 472.0 1.4936 66900.0 28.589353
1 1129.0 463.0 1.8200 80100.0 28.589353
2 333.0 117.0 1.6509 85700.0 28.589353 '''
'기타(🎸X) > 빅데이터' 카테고리의 다른 글
[빅데이터] 파이썬 빅데이터 분석 패키지 - scikit-learn (0) | 2023.05.30 |
---|---|
[빅데이터] 파이썬 빅데이터 분석 패키지 - numpy (0) | 2023.05.28 |
[빅데이터] 데이터 비식별화 기법 (0) | 2023.05.09 |
[빅데이터] 빅데이터 플랫폼 (0) | 2023.02.25 |
[빅데이터] 빅데이터 조직 및 인력 (0) | 2023.02.24 |
댓글