Python_Pandas 01

고지현·2023년 6월 23일

Python_Pandas

목록 보기
1/5
post-thumbnail

Pandas?

  • 대부분의 데이터는 시계열(series)나 표(table)로 나타낼 수 있음
  • 판다스(Pandas)는 이러한 데이터를 다루기 위한 시리즈(Series) 클래스와 데이터 프레임(DataFrame) 클래스를 제공

시리즈 (Series)

  • 시리즈는 Numpy에서 제공하는 1차원 배열과 비슷
  • 각 데이터의 의미(이름)를 표시하는 인덱스(index)를 붙일 수 있음

    데이터 자체는 값(value)라고 함
    시리즈 = 값(value) + 인덱스(index)

시리즈 생성

  • 데이터를 리스트나 1차원 배열 형식으로 Series 클래스 생성자에 넣어주면 시리즈 클래스 객체를 만들 수 있음
  • 이 때 인덱스의 길이는 데이터의 길이와 같아야 함
  • 인덱스의 값을 인덱스 라벨(label)이라고도 함
  • 인덱스 라벨은 문자열 뿐 아니라 날짜, 시간, 정수 등도 가능
data = [9904312, 3448737, 2890451, 2466052]
index = ["서울", "부산", "인천", "대구"]
s = pd.Series(data, index=index)
s
서울    9904312
부산    3448737
인천    2890451
대구    2466052
dtype: int64
  • 만약 인덱스를 지정하지 않고 시리즈를 만들면 시리즈의 인덱스는 0부터 시작하는 정수값이 됨
pd.Series(range(10, 14)), pd.Series(range(10, 14), index=range(4))
(0    10
 1    11
 2    12
 3    13
 dtype: int64,
 0    10
 1    11
 2    12
 3    13
 dtype: int64)
  • 시리즈의 인덱스는 index 속성으로 접근할 수 있음
  • 시리즈의 값은 1차원 배열이며 values 속성으로 접근할 수 있음
s, s.index, s.values
(도시
 서울    9904312
 부산    3448737
 인천    2890451
 대구    2466052
 Name: 인구, dtype: int64,
 Index(['서울', '부산', '인천', '대구'], dtype='object', name='도시'),
 array([9904312, 3448737, 2890451, 2466052]))
  • name 속성을 이용하여 시리즈 데이터에 이름을 붙일 수 있음
  • index.name 속성으로 시리즈의 인덱스에도 이름을 붙일 수 있음
s.name = '인구'
s.index.name = '도시'
s
도시
서울    9904312
부산    3448737
인천    2890451
대구    2466052
Name: 인구, dtype: int64

시리즈 연산

  • 넘파이 배열처럼 시리즈도 벡터화 연산을 할 수 있음
  • 다만 연산은 시리즈의 값에만 적용되며 인덱스 값은 변하지 않음
 s / 1_000_000 # 인덱스에는 영향이 미치지 않고 값에만 영향이 미친다
도시
서울    9.904312
부산    3.448737
인천    2.890451
대구    2.466052
Name: 인구, dtype: float64

시리즈 인덱싱 & 슬라이싱

  • 시리즈는 Numpy 배열에서 가능한 인덱스 방법 이외에도 인덱스 라벨을 이용한 인덱싱도 할 수 있음
  • 배열 인덱싱이나 인덱스 라벨을 이용한 슬라이싱(slicing)도 가능
s[1], s["부산"], s[3], s[-1], s['대구']
(3448737, 3448737), (2466052, 2466052, 2466052)
s[['부산', '서울', '대구', '서울']]
도시
부산    3448737
서울    9904312
대구    2466052
서울    9904312
Name: 인구, dtype: int64
# 인구가 250만 초과, 500만 미만인 경우
s[(250e4 < s) & (500e4 > s) ]
도시
부산    3448737
인천    2890451
Name: 인구, dtype: int64
  • 슬라이싱을 해도 부분적인 시리즈를 반환
  • 이 때 문자열 라벨을 이용한 슬라이싱을 하는 경우에는 숫자 인덱싱과 달리 콜론(:) 기호 뒤에 오는 값도 결과에 포함되므로 주의
s[1:3] # 두번째(1)부터 세번째(2)까지
도시
부산    3448737
인천    2890451
Name: 인구, dtype: int64
  • 만약 라벨 값이 (변수로 표기할 수 있는) 문자열경우에는 인덱스 라벨이 속성인것처럼 점(.)을 이용하여 해당 인덱스 값에 접근할 수도 있음
s0 = pd.Series(np.arange(3), index=list('abc'))
s0['a'], s0.a

시리즈와 딕셔너리 자료형

  • 시리즈 객체는 라벨 값에 의해 인덱싱이 가능하므로 실질적으로 인덱스 라벨 값을 키(key)로 가지는 딕셔너리 자료형과 유사

  • 따라서 딕셔너리 자료형에서 제공하는 in 연산도 가능하고 items 메서드를 사용하면 for 루프를 통해 각 원소의 키(key)와 값(value)을 접근할 수도 있음

"서울" in s, "서울" in s.index # 시리즈 s 안에 '서울'이라는 인덱스 라벨(키)가 있는지 여부 
(True, True)
# for i in s.items()
for k,v in s.items():
  # print(i)
  print(f"{k} = {v}")
서울 = 9904312
부산 = 3448737
인천 = 2890451
대구 = 2466052
  • 딕셔너리 객체에서 시리즈를 만들 수도 있음
s2 = pd.Series({
    "서울": 9631482,
    "부산": 3393191,
    "인천": 2632035,
    "대전": 1490158
})
s2
서울    9631482
부산    3393191
인천    2632035
대전    1490158
dtype: int64
  • 딕셔너리의 원소는 순서를 가지지 않으므로 시리즈의 데이터도 순서가 보장되지 않음
  • 만약 순서를 정하고 싶다면 인덱스를 리스트로 지정해야 함
s2 = pd.Series({
    "서울": 9631482,
    "부산": 3393191,
    "인천": 2632035,
    "대전": 1490158
}, index=["부산", "서울", "인천", "대전"])
s2
부산    3393191
서울    9631482
인천    2632035
대전    1490158
dtype: int64

인덱스 기반 연산

  • 두 시리즈에 대해 연산을 하는 경우 인덱스가 같은 데이터에 대해서만 차이를 구함
ds = s - s2
대구         NaN
대전         NaN
부산     55546.0
서울    272830.0
인천    258416.0
dtype: float64
s.values - s2.values # 강제로 위치로 계산한 것이기 때문에 정확한 것이 아니다.
array([272830,  55546, 258416, 975894])
# NaN인 값을 구하고 싶다면 null 메소드를 사용
ds.isnull(), ds.notnull()
(대구     True
 대전     True
 부산    False
 서울    False
 인천    False
 dtype: bool,
 대구    False
 대전    False
 부산     True
 서울     True
 인천     True
 dtype: bool)`
ds[ds.isnull()], ds[ds.notnull()]
(대구   NaN
 대전   NaN
 dtype: float64,
 부산     55546.0
 서울    272830.0
 인천    258416.0
 dtype: float64)
# 인구 증가율 구하기 (%)
rs = (s -s2) / s2 * 100
# rs = rs[rs.notnull()]
rs = rs.dropna()
rs
부산    1.636984
서울    2.832690
인천    9.818107
dtype: float64

데이터의 갱신, 추가, 삭제

  • 인덱싱을 이용하여 딕셔너리처럼 데이터를 갱신(update) 혹은 추가(add)
rs['부산'] = 1.63
rs
부산    1.630000
서울    2.832690
인천    9.818107
dtype: float64

데이터프레임 (DataFrame)

  • 시리즈가 1차원 배열 데이터에 행방향 인덱스(row index)를 붙인 것이라면 데이터프레임는 2차원 행렬 데이터에 인덱스를 붙인 것
  • 2차원이므로 각각의 행 데이터의 이름이 되는 행 인덱스(row index) 뿐 아니라 각각의 열 데이터의 이름이 되는 열 인덱스(column index)도 붙일 수 있음.

데이터프레임 생성

  1. 하나의 열이 되는 데이터를 리스트나 일차원 배열을 준비
  2. 이 각각의 열에 대한 이름(라벨)을 키로 가지는 딕셔너리를 생성
  3. 이 데이터를 DataFrame 생성자에 넣음. 동시에 열방향 인덱스는 columns 인수로, 행방향 인덱스는 index 인수로 지정
import pandas as pd

data = {
    "2015": [9904312, 3448737, 2890451, 2466052],
    "2010": [9631482, 3393191, 2632035, 2431774],
    "2005": [9762546, 3512547, 2517680, 2456016],
    "2000": [9853972, 3655437, 2466338, 2473990],
    "지역": ["수도권", "경상권", "수도권", "경상권"],
    "2010-2015 증가율": [0.0283, 0.0163, 0.0982, 0.0141]
}
columns = ["지역", "2015", "2010", "2005", "2000", "2010-2015 증가율"]
index = ["서울", "부산", "인천", "대구"]

df = pd.DataFrame(data, columns=columns, index=index)
df
지역	2015	2010	2005	2000	2010-2015 증가율
서울	수도권	9904312	9631482	9762546	9853972	0.0283
부산	경상권	3448737	3393191	3512547	3655437	0.0163
인천	수도권	2890451	2632035	2517680	2466338	0.0982
대구	경상권	2466052	2431774	2456016	2473990	0.0141
  • 데이터프레임은 공통 인덱스를 가지는 열 시리즈(column series)를 딕셔너리로 묶어놓은 것이라고 보는 것이 더 정확
  • 데이터프레임은 각 열(column)마다 자료형이 다를 수 있음 (2차원 배열이라고 보기엔 무리)

  • 데이터만 접근하려면 values 속성 사용
  • 열방향 인덱스 : columns 속성
  • 행방향 인덱스 : index 속성
df.values
array([['수도권', 9904312, 9631482, 9762546, 9853972, 0.0283],
       ['경상권', 3448737, 3393191, 3512547, 3655437, 0.0163],
       ['수도권', 2890451, 2632035, 2517680, 2466338, 0.0982],
       ['경상권', 2466052, 2431774, 2456016, 2473990, 0.0141]], dtype=object)
df.columns
Index(['지역', '2015', '2010', '2005', '2000', '2010-2015 증가율'], dtype='object')
df.index
df.index
Index(['서울', '부산', '인천', '대구'], dtype='object')
# 시리즈처럼 열방향 인덱스와 행방향 인덱스에 이름을 붙이는 것도 가능
df.index.name = '도시'
df.columns.name = '특성'
df
특성	지역	2015	2010	2005	2000	2010-2015 증가율
도시						
서울	수도권	9904312	9631482	9762546	9853972	0.0283
부산	경상권	3448737	3393191	3512547	3655437	0.0163
인천	수도권	2890451	2632035	2517680	2466338	0.0982
대구	경상권	2466052	2431774	2456016	2473990	0.0141

열 데이터의 갱신, 추가, 삭제

  • 데이터프레임은 열 시리즈의 딕셔너리으로 볼 수 있으므로 열 단위로 데이터를 갱신하거나 추가, 삭제할 수 있음
df['지역'], type[df['지역']]
(도시
 서울    수도권
 부산    경상권
 인천    수도권
 대구    경상권
 Name: 지역, dtype: object,
 type[도시
 서울    수도권
 부산    경상권
 인천    수도권
 대구    경상권
 Name: 지역, dtype: object])
df['2010-2015 증가율'] = df['2010-2015 증가율'] * 100
df.head()
특성	지역	2015	2010	2005	2000	2010-2015 증가율
도시						
서울	수도권	9904312	9631482	9762546	9853972	2.83
부산	경상권	3448737	3393191	3512547	3655437	1.63
인천	수도권	2890451	2632035	2517680	2466338	9.82
대구	경상권	2466052	2431774	2456016	2473990	1.41

열 인덱싱

  • 데이터프레임은 열 라벨을 키로, 열 시리즈를 값으로 가지는 딕셔너리와 유사
  • 따라서 데이터프레임을 인덱싱을 할 때도 열 라벨(column label)을 키값으로 생각하여 인덱싱을 할 수 있음
  • 인덱스로 라벨 값을 하나만 넣으면 시리즈 객체가 반환되고 라벨의 배열 또는 리스트를 넣으면 부분적인 데이터프레임이 반환
# 하나의 열만 인덱싱하면 시리즈가 반환
df['지역']
도시
서울    수도권
부산    경상권
인천    수도권
대구    경상권
Name: 지역, dtype: object
# 여러개의 열을 인덱싱하면 부분적인 데이터프레임이 반환
df[['2010', '2015']]
특성	2010	2015
도시		
서울	9631482	9904312
부산	3393191	3448737
인천	2632035	2890451
대구	2431774	2466052
  • 만약 하나의 열만 빼내면서 데이터프레임 자료형을 유지하고 싶다면 원소가 하나인 리스트를 써서 인덱싱
특성	2010
도시	
서울	9631482
부산	3393191
인천	2632035
대구	2431774
type(df['2010'])
pandas.core.series.Series
  • 데이터프레임의 열 인덱스가 문자열 라벨을 가지고 있는 경우에는 순서를 나타내는 정수 인덱스를 열 인덱싱에 사용할 수 없음
  • 정수 인덱싱의 슬라이스는 행(row)을 인덱싱할 때 사용하므로 열을 인덱싱할 때는 쓸 수 없음 (정수 인덱스를 넣으면 KeyError 오류가 발생)
  • 다만 원래부터 문자열이 아닌 정수형 열 인덱스를 가지는 경우에는 인덱스 값으로 정수를 사용할 수 있음
df2 = pd.DataFrame(np.arange(12).reshape(3, -1))
df2
	0	1	2	3
0	0	1	2	3
1	4	5	6	7
2	8	9	10	11
df2[1]
0    1
1    5
2    9
Name: 1, dtype: int64
df2[[1, 2]]
1	2
0	1	2
1	5	6
2	9	10
### 행 인덱싱
* 만약 행 단위로 인덱싱을 하고자 하면 항상 슬라이싱(slicing)을 해야함
* 인덱스의 값이 문자 라벨이면 라벨 슬라이싱도 가능
df
특성	지역	2015	2010	2005	2000	2010-2015 증가율
도시						
서울	수도권	9904312	9631482	9762546	9853972	2.83
부산	경상권	3448737	3393191	3512547	3655437	1.63
인천	수도권	2890451	2632035	2517680	2466338	9.82
대구	경상권	2466052	2431774	2456016	2473990	1.41
df[0:1], df[:1]
(특성   지역     2015     2010     2005     2000  2010-2015 증가율
 도시                                                        
 서울  수도권  9904312  9631482  9762546  9853972           2.83,
 특성   지역     2015     2010     2005     2000  2010-2015 증가율
 도시                                                        
 서울  수도권  9904312  9631482  9762546  9853972           2.83)

개별 데이터 인덱싱

  • 데이터프레임에서 열 라벨로 시리즈를 인덱싱하면 시리즈가 됨. 이 시리즈를 다시 행 라벨로 인덱싱하면 개별 데이터가 나옴.

데이터 프레임 인덱싱 방법 정리

인덱싱 값가능결과자료형추가사항
라벨O시리즈
라벨 리스트O데이터프레임
인덱스 데이터 (정수)X열 라벨이 정수인 경우에는 라벨 인덱싱으로 인정
인덱스 데이터(정수) 슬라이스O데이터프레임

데이터 입출력

CSV 파일 입력

# comma seperated values : comma(,)로 구분된 값들
# 샘플 데이터 만들기
%%writefile sample1.csv
c1,c2,c3
1,1.11,one
2,2.22,two
3,3.33,three
Writing sample1.csv
# pd.read_csv(파일이름) : CSV파일로부터 데이터를 읽어 데이터프레임 만들기
pd.read_csv('sample1.csv')
c1	c2	c3
0	1	1.11	one
1	2	2.22	two
2	3	3.33	three
# 만약 데이터 파일에 열 인덱스 정보가 없는 경우에는 read_csv 명령의 names 인수로 설정 가능
%%writefile sample2.csv
1, 1.11, one
2, 2.22, two
3, 3.33, three
Writing sample2.csv
pd.read_csv('sample2.csv')
1	1.11	one
0	2	2.22	two
1	3	3.33	three
pd.read_csv('sample2.csv', names=['c1', 'c2', 'c3']) # names=[열 이름 리스트]
c1	c2	c3
0	1	1.11	one
1	2	2.22	two
2	3	3.33	three
# 만약 테이블 내의 특정한 열을 행 인덱스로 지정하고 싶으면 index_col 인수를 사용
pd.read_csv('sample2.csv', names=['c1', 'c2', 'c3'], index_col=2) # index_col=n번째를 지정(0부터 ->index)
c1	c2
c3		
one	1	1.11
two	2	2.22
three	3	3.33

CSV 파일 출력

df = pd.read_csv('sample1.csv')
df
c1	c2	c3
0	1	1.11	one
1	2	2.22	two
2	3	3.33	three
df['c4'] = df['c1'] + df['c2']
df
c1	c2	c3	c4
0	1	1.11	one	2.11
1	2	2.22	two	4.22
2	3	3.33	three	6.33

인터넷 상의 CSV 파일 입력

  • 웹상에는 다양한 데이터 파일이 CSV 파일 형태로 제공
  • read_csv 명령 사용시 파일 패스 대신 URL을 지정하면 Pandas가 직접 해당 파일을 다운로드하여 읽어들임
url = 'https://raw.githubusercontent.com/qus0in/230621_pandas/main/titanic.csv'
titanic_df = pd.read_csv(url)
titanic_df
  • 만약 앞이나 뒤의 특정 갯수만 보고 싶다면 head 메서드나 tail 메서드를 이용
  • 메소드 인수로 출력할 행의 수를 넣을 수도 있음
titanic_df.head()
titanic_df.tail()

0개의 댓글