2024.01.01 TIL

녹차·2024년 1월 1일

TIL_Python

목록 보기
1/9

2024.01.01 TIL

학습주제

  • pandas 입문, 데이터셋을 통한 다양한 예제, 깊은복사 vs 얉은복사

데이터셋 준비하기

  • excel 파일 읽고 데이터프레임(Dataframe)만들기
# read_excel : 엑셀 파일 읽기
df = pd.read_excel('./slamdunk_player_stats.xlsx')
df

데이터프레임 구조 가볍게 보기

  • 앞쪽 뒤쪽 데이터를 확인하는 head(), tail()
# 앞쪽 5줄
df.head()
이름포지션소속신장체중
0채치수센터북산19790
1강백호파워포워드북산18983
2서태웅스몰포워드북산18775
3정대만슈팅가드북산18470
4정병욱센터북산18078
💡 5줄이 기본이다.
# 앞쪽 3줄
df.head(3)
이름포지션소속신장체중
0채치수센터북산19790
1강백호파워포워드북산18983
2서태웅스몰포워드북산18775
# 뒤쪽 3줄
df.tail(3)
이름포지션소속신장체중
23이정환포인트가드해남18479
24김수겸포인트가드상양17866
25김준일포인트가드삼포18674

행 조회 (loc, iloc, slicing)

  • Row(행) 데이터를 선택(조회)하기 - index, slice, loc, iloc
# series로 인덱스 레이블 선택(조회)하기
df.loc[1]
이름        강백호
포지션     파워포워드
소속         북산
신장        189
체중         83
골밑슛        80
미들슛        32
3점슛        21
덩크슛        93
레이업        90
패스         54
파워         90
방해저항       58
도약        100
런닝         96
드리블        56
리바운드      107
블록         88
방해         85
스틸         66
Name: 1, dtype: object
# dataframe으로 인덱스 선택(조회)하기
df.loc[[1]]
💡 데이터프레임 형식으로 보고 싶으면 []안에 넣으면 된다.
이름포지션소속신장체중골밑슛
1강백호파워포워드북산1898380
# 여러 행 조회하기
df.loc[[3, 6, 9]]
이름포지션소속신장체중
3정대만슈팅가드북산18470
6신오일슈팅가드북산17063
9고민구센터해남19180
df.loc[[3, 6, 9], ["이름", "체중"]]
이름체중
3정대만70
6신오일63
9고민구80
# 범위로 조회하기
df.loc[3:7, "이름":"체중"]
이름포지션소속신장
3정대만슈팅가드북산184
4정병욱센터북산180
5권준호스몰포워드북산178
6신오일슈팅가드북산170
7송태섭포인트가드북산168
# 슬라이싱 기법으로 조회하기1
df.loc[3:8:2]

# 슬라이싱 기법으로 조회하기2
df.loc[:, ["이름", "포지션", "소속", "리바운드"]]
# index location으로 조회를 하고 싶다면 - iloc
df.iloc[3:7, 0:5]

인덱스 3번부터 6번까지 0~4의 열의 데이터가 출력된다.
  • Column(열) 데이터를 선택(조회)하기
# 단일 컬럼 '이름'의 시리즈 출력하기
df['이름']
0     채치수
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    김준일
Name: 이름, dtype: object
# 이름 열 조회하기.head()
df['이름'].head()
0    채치수
1    강백호
2    서태웅
3    정대만
4    정병욱
Name: 이름, dtype: object
# 이렇게 하면 DataFrame -> 2차원 데이터
df[['이름']]
이름
0채치수
1강백호
2서태웅
💡 역시 데이터 프레임 형식으로 보고 싶으면 [] 안에 삽입하면 된다.
# 다중 컬럼(열) 조회하기
df[['이름', '신장', '소속']].head(7)

# 이름 신장 소속의 데이터만을 출력할 수 있다.

Series

  • 데이터프레임 = 시리즈 n개 이상 이루어져있다. 💡 특정 부분을 볼 수 있는데, 이 때 데이터프레임, 시리즈로도 볼 수 있다! - 수정을 할 수 있다. - 데이터 프레임 특정 한 줄 수정하고 싶다. - 데이터 프레임_시리즈 = 동일한 규모에 시리즈 - **조건에 따라 특정 데이터만 조회할 때 시리즈를 사용**

기술 통계

# 데이터프레임 확인
df.describe()
신장
count26.000000
mean183.384615
std10.350177
min160.000000
25%178.000000
50%185.000000
75%189.750000
max202.000000
  • describe를 사용하면 여러가지 통계를 출력할 수 있다.
    • count = 합
    • mean = 평균
    • std = 표준편차
    • min = 최솟값
    • max = 최댓값
    • 50% = min과 max사이의 50퍼센트 값 (중간 값)

문자 탐색 (str 활용)

# .str
df["이름"].str
# .str.contains 포함 글씨 확인
df["이름"].str.contains("정")
0     False
1     False
2     False
3      True
4      True
5     False
6     False
7     False
8     False
9     False
10    False
11    False
12    False
13    False
14    False
15    False
16    False
17    False
18    False
19    False
20    False
21    False
22     True
23     True
24    False
25    False
Name: 이름, dtype: bool
  • 이름에 정이 들어가면 True 아니면 False를 반환하도록 한다.
# sum을 하면 True 개수를 알 수 있다.
sum(df["이름"].str.contains("정"))

4

# 앞으로는 이런 체인형을 지향할 예정
df["이름"].str.contains("정").sum()

4

# T/F로 이루어진 boolean형 시리즈 또는 배열로 True에 해당하는 값들만 조회할 수 있다.
df[df["이름"].str.contains("정")]
  • 이름에 정이 들어간 경우의 데이터프레임만 출력하도록 한다.
이름포지션소속신장
3정대만슈팅가드북산184
4정병욱센터북산180
22백정태포인트가드능남179
23이정환포인트가드해남184
  • 특정 위치 인덱스만 탐색
# 정씨 인가? T/F로 이루어진 시리즈 생성
df["이름"].str[0]=="정"
  • 정씨인 사람만 출력하도록 인덱스를 이용하였다.
    • 첫번째 글자가 정인 사람만 시리즈 생성
# 정씨에 해당하는 데이터프레임 생성
df[df["이름"].str[0]=="정"]
이름포지션소속신장
3정대만슈팅가드북산184
4정병욱센터북산180

수치 탐색과 산술 연산

데이터프레임의 각 값은 for문을 거치지 않고도 각자 수행할 수 있다. 이를 이용해보자.

# 180보다 큰 사람인 T/F시리즈 만들기
df['신장'] > 180
0      True
1      True
2      True
3      True
4     False
5     False
6     False
7     False
8     False
9      True
10     True
11     True
12     True
13     True
14     True
15     True
16     True
17     True
18     True
19    False
20    False
21    False
22    False
23     True
24    False
25     True
Name: 신장, dtype: bool
# 모든 선수 신장 100 추가하기
df['신장']+100

별도의 DataFrame 생성

원하는 DataFrame을 생성하고 변수에 저장해보자

# 포지션이 센터에 해당되는 사람만 가진 경우
df_center = df[df["포지션"]=="센터"]
df_center
이름포지션소속신장
0채치수센터북산197
4정병욱센터북산180
9고민구센터해남191
12변덕규센터능남202
13성현준센터상양197

apply()

# df_power 신장을 늘린 시리즈 만들기
df_power["신장"].apply(lambda x : x+100)
# 기존 체이블에서 신장 늘린 시리즈를 교체하기
df_power["신장"] = df_power["신장"].apply(lambda x : x+100)
df_power.head()
이름신장체중패스
0채치수2979070
1강백호2898354
2서태웅28775100
3정대만2847082
4정병욱2807878
# 기존 체이블에서 신장 늘린 시리즈를 교체하기
df_power["new_신장"] = df_power["신장"].apply(lambda x : x+100)
df_power.head()
이름신장체중패스new_신장
0채치수2979070397
1강백호2898354389
2서태웅28775100387
3정대만2847082384
4정병욱2807878380
# 파이썬에서 for과 원본데이터를 조작할 때 의도치 않은 상황
numbers = [0, 1, 2, 3, 4, 5, 6, 7]
for n in numbers:
    print(n)
    numbers.remove(n)
print(numbers)
0
2
4
6
[1, 3, 5, 7]
🚫 이런 경우 n이 numbers의 원본데이터와 직접 적으로 연결되어 있기 때문에 n을 삭제하면 numbers에서도 삭제됨
# 파이썬에서 for을 이용한 유사한 상황 - .copy()나 [:]로 해결
numbers = [0, 1, 2, 3, 4, 5, 6, 7]
for n in numbers.copy():
    print(n)
    numbers.remove(n)
print(numbers)
0
1
2
3
4
5
6
7
[]
👍 copy를 사용하면 해결할 수 있음

열(col) 삭제 - del df['열이름']

# del df['열이름'] -> Series
del df_power_new['패스평가']

행(row)삭제 - df.drop([index])

database sql의 drop과 비슷
파이썬 list index(숫자로만 이뤄진 것이 아닌) database index로 생각(숫자가 아니여도 되는)

# .drop()으로 삭제 -> **비파괴적인 처리**
df_power_new.drop(0).head()
💡 비파과적인 처리를 하면 원본데이터에는 아무런 처리가 적용되지 않음
# 비파괴적인 처리기 때문에 1. 저장이 필요
df_power_new = df_power_new.drop(5)
df_power_new.head()
# 파괴적인 처리를 위한 2. inplace=True
df_power_new.drop(2, inplace=True)
df_power_new.head()
💡 위의 2가지 방법으로 파괴적인 처리를 할 수 있음

열 이름 변경 -.rename(columns = {'기존':'변경'}, inplace=True/False)

.rename의 docstring을 보면 index 등도 변경할 수 있다.

# 비파괴적인 처리 - 원본은 바뀌지 않는다
df_power_new.rename(columns={'신장':'키', '체중':'몸무게'})
df_power_new.head()
  • 신장이 키로 이름이 바뀌고, 체중이 몸무게로 이름이 바뀐다.
# 파괴적인 처리를 위해 inplace=True
df_power_new.rename(columns={'신장':'키', '체중':'몸무게'}, inplace=True)
df_power_new.head()
  • inplace**=True** 를 추가하여 파괴적인 처리 진행

정렬 - .sort_index(), .sort_values()

# 값 정렬 + 파괴적 처리
df_power_new.sort_values(by='키', inplace=True)
df_power_new.head()
이름몸무게패스
21홍익현1604284
8이달재1645798
7송태섭16859100
6신오일1706378
20안영수1746285
# 값 정렬(내림차순) + 파괴적 처리
df_power_new.sort_values(by='키', inplace=True, ascending=False)
df_power_new.head()
이름몸무게패스
12변덕규2029053
13성현준1978380
17구대철1968233
9고민구1918076
14윤대협1907992

피벗 테이블 - pivot_table

엑셀, 스프레드 시트의 피봇 테이블과 동일합니다.

# '신장'을 index로 지정한 pivot_df 생성하기
# aggfunc : 집계함수(aggregate function)
# aggfunc=np.sum, aggfunc=sum, aggfunc='sum'도 모두 되긴 한다.
pivot_df = pd.pivot_table(df, index='신장', values=['3점슛', '골밑슛'], aggfunc='mean')
pivot_df.round(2)
신장3점슛골밑슛
160105.087.00
16458.082.00
16862.080.00
17080.083.00
17495.085.00

애초에 pandas의 표기 수치를 바꾸는 방법도 있다.
pd.options.display.float_format = '{:.2f}'.format

얕은 복사(Shallow Copy) vs 깊은 복사(Deep Copy)

profile
가장 예쁜 꽃은 우여곡절 끝에 피는 꽃

0개의 댓글