본문 바로가기
Python/판다스 데이터 분석

판다스 패키지 소개

by 준보틱스 2024. 6. 26.

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

pandas 패키지 import

>>> import pandas as pd

Series 클래스

Series 클래스는 넘파이에서 제공하는 1차원 배열과 비슷하지만 각 데이터의 의미를 표시하는 인덱스(index)를 붙일 수 있다. 데이터 자체는 값(value)라고 한다.

- 시리즈 = 값(value) + 인덱스(index)

시리즈 생성

데이터를 리스트나 1차원 배열 형식으로 Series 클래스 생성자에 넣어주면 시리즈 클래스 객체를 만들 수 있다. 이 때 인덱스의 길이는 데이터의 길이와 같아야 한다.

>>> import pandas as pd
>>> a = pd.Series([1,2,3,4],
                  index=['kim','lee','park','choi'])
>>> print(a)
kim     1
lee     2
park    3
choi    4
dtype: int64

 

만약 index를 지정하지 않으면 자동으로 인덱스는 0부터 시작하는 정수값이 된다.

>>> import pandas as pd

>>> a = pd.Series([1,2,3,4])

>>> print(a)
0    1
1    2
2    3
3    4
dtype: int64

 

시리즈의 인덱스는 index 속성으로 접근할 수 있다. 시리즈의 값은 1차원 배열이며 values 속성으로 접근할 수 있다.

>>> import pandas as pd

>>> a = pd.Series([1,2,3,4],
                  index=['kim','lee','park','choi'])

>>> print(a.index)
Index(['kim', 'lee', 'park', 'choi'], dtype='object')
>>> import pandas as pd

>>> a = pd.Series([1,2,3,4],
                  index=['kim','lee','park','choi'])

>>> print(a.values)
[1 2 3 4]

 

name 속성을 이용해 시리즈 데이터에 이름을 붙일 수 있다. index.name 속성으로 시리즈의 인덱스에도 이름을 붙일 수 있다.

>>> import pandas as pd

>>> a = pd.Series([1,2,3,4],
                  index=['kim','lee','park','choi'])

>>> a.name = "number"
>>> a.index.name = 'name'

>>> print(a)
name
kim     1
lee     2
park    3
choi    4
Name: number, dtype: int64

 

시리즈 연산

넘파이 배열처럼 시리즈도 벡터화 연산을 할 수 있다. 다만 연산은 시리즈의 값에만 적용되며 인덱스 값은 변하지 않는다. 예를 들어 숫자를 백만단위로 만들기 위해 시리즈 객체를 1,000,000으로 곱해도 인덱스 라벨에는 영향을 미치지 않는 것을 볼 수 있다.

>>> import pandas as pd

>>> s = pd.Series([1,2,3,4],
                  index=["kim","lee","park","choi"])

>>> print(s * 1000000)
kim     1000000
lee     2000000
park    3000000
choi    4000000
dtype: int64

 

시리즈 인덱싱

시리즈는 넘파이 배열에서 가능한 인덱스 방법 이외에도 인덱스 라벨을 이용한 인덱싱도 할 수 있다. 배열 인덱싱이나 인덱스 라벨을 이용한 슬라이싱(slicing)도 가능하다.

>>> import pandas as pd

>>> s = pd.Series([1,2,3,4],
                  index=["kim","lee","park","choi"])

>>> print(s[1])
>>> print(s["lee"])
2
2

 

배열 인덱싱을 하면 부분적인 값을 가지는 시리즈 자료형을 반환한다. 자료의 순서를 바꾸거나 특정한 자료만 선택할 수 있다.

>>> import pandas as pd

>>> s = pd.Series([1,2,3,4],
                  index=["kim","lee","park","choi"])

>>> print(s[[0,3,1]])
>>> print(s[(1 < s) & (s < 4)])
kim     1
choi    4
lee     2
dtype: int64
lee     2
park    3
dtype: int64

 

슬라이싱을 해도 부분적인 시리즈를 반환한다. 이 때 문자열 라벨을 이용한 슬라이싱을 하는 경우에는 숫자 인덱싱과 달리 콜론(:) 기호 뒤에 오는 값도 결과에 포함되므로 주의해야 한다.

>>> import pandas as pd

>>> s = pd.Series([1,2,3,4],
                  index=["kim","lee","park","choi"])

>>> print(s[1:3])
lee     2
park    3
dtype: int64

 

만약 라벨 값이 영문 문자열인 경우에는 인덱스 라벨이 속성인 것 처럼 점(.)을 이용해 해당 인덱스 값에 접근할 수 있다.

>>> import pandas as pd

>>> s = pd.Series(range(3), index=["a","b","c"])

>>> print(s.a)
>>> print(s.b)
0
1

 

시리즈와 딕셔너리 자료형

시리즈 객체는 라벨 값에 의해 인덱싱이 가능하므로 실질적으로 인덱스 라벨 값을 키(key)로 가지는 딕셔너리 자료형과 같다고 볼 수 있다. 따라서 딕셔너리 자료형에서 제공하는 in 연산도 가능하고 items 메서드를 사용하면 for 반복문을 통해 각 원소의 키(key)와 값(value)을 접근할 수 있다.

>>> import pandas as pd

>>> s = pd.Series([1,2,3,4],
                  index=["kim","lee","park","choi"])

>>> print("park" in s)
>>> print("yu" in s)
True
False
>>> import pandas as pd

>>> s = pd.Series([1,2,3,4],
                  index=["kim","lee","park","choi"])

>>> for k, v in s.items():
        print("%s = %d" % (k,v))
kim = 1
lee = 2
park = 3
choi = 4

 

또 딕셔너리 객체에서 시리즈를 만들 수 있다.

>>> import pandas as pd

>>> s = pd.Series({"kim": 1,"lee": 2,"park": 3,"choi": 4})

>>> print(s)
kim     1
lee     2
park    3
choi    4
dtype: int64

 

딕셔너리의 원소는 순서를 가지지 않으므로 시리즈의 데이터도 순서가 보장되지 않는다. 만약 순서를 정하고 싶다면 인덱스를 리스트로 지정해야 한다.

>>> import pandas as pd

>>> s = pd.Series({"kim": 1,"lee": 2,"park": 3,"choi": 4},
                  index=["lee", "kim", "park", "choi"])

>>> print(s)
lee     2
kim     1
park    3
choi    4
dtype: int64

데이터프레임 클래스

시리즈가 1차원 벡터 데이터에 행방향 인덱스(row index)를 붙인 것이라면 데이터프레임(DataFrame) 클래스는 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, index=index, columns=columns)
>>> print(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

 

시리즈와 마찬가지로 데이터만 접근하려면 values 속성을 사용한다. 열방향 인덱스와 행방향 인덱스는 각각 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, index=index, columns=columns)
>>> print(df.values)
>>> print(df.columns)
>>> print(df.index)
[['수도권' 9904312 9631482 9762546 9853972 0.0283]
 ['경상권' 3448737 3393191 3512547 3655437 0.0163]
 ['수도권' 2890451 2632035 2517680 2466338 0.0982]
 ['경상권' 2466052 2431774 2456016 2473990 0.0141]]
Index(['지역', '2015', '2010', '2005', '2000', '2010-2015 증가율'], dtype='object')
Index(['서울', '부산', '인천', '대구'], dtype='object')

 

시리즈처럼 열방향 인덱스와 행방향 인덱스에 이름을 붙이는 것도 가능하다.

>>> 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, index=index, columns=columns)

>>> df.index.name = "도시"
>>> df.columns.name = "특성"

>>> print(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

 

데이터프레임은 전치(transpose)를 포함하여 넘파이 2차원 배열이 가지는 대부분의 속성이나 메서드를 지원한다.

>>> 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, index=index, columns=columns)

>>> df.index.name = "도시"
>>> df.columns.name = "특성"

>>> print(df.T)
도시                  서울       부산       인천       대구
특성
지역                 수도권      경상권      수도권      경상권
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

 

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

데이터프레임은 열 시리즈의 딕셔너리로 볼 수 있으므로 열 단위로 데이터를 갱신하거나 추가 및 삭제할 수 있다.

>>> 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"]
>>> index = ["서울", "부산", "인천", "대구"]

>>> df = pd.DataFrame(data, index=index, columns=columns)

>>> df.index.name = "도시"
>>> df.columns.name = "특성"

>>> print(df)
특성   지역     2015     2010     2005     2000
도시
서울  수도권  9904312  9631482  9762546  9853972
부산  경상권  3448737  3393191  3512547  3655437
인천  수도권  2890451  2632035  2517680  2466338
대구  경상권  2466052  2431774  2456016  2473990

 

위 소스코드에서 2010-2015 증가율을 100배 곱해서 출력한다.

>>> 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, index=index, columns=columns)

>>> df.index.name = "도시"
>>> df.columns.name = "특성"
>>> df["2010-2015 증가율"] = df["2010-2015 증가율"] * 100

>>> print(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

 

여기서 "2005-2010 증가율" 이라는 이름의 열을 추가해본다.

>>> 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, index=index, columns=columns)

>>> df.index.name = "도시"
>>> df.columns.name = "특성"

>>> df["2010-2015 증가율"] = df["2010-2015 증가율"] * 100
>>> df["2005-2010 증가율"] = ((df["2010"] - df["2005"]) / df["2005"] * 100).round(2)

>>> print(df)
특성   지역     2015     2010     2005     2000  2010-2015 증가율  2005-2010 증가율
도시
서울  수도권  9904312  9631482  9762546  9853972           2.83          -1.34
부산  경상권  3448737  3393191  3512547  3655437           1.63          -3.40
인천  수도권  2890451  2632035  2517680  2466338           9.82           4.54
대구  경상권  2466052  2431774  2456016  2473990           1.41          -0.99

 

또한 열 삭제도 가능하다. "2010-2015 증가율" 이라는 열을 삭제해보자.

>>> 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, index=index, columns=columns)

>>> df.index.name = "도시"
>>> df.columns.name = "특성"

>>> df["2010-2015 증가율"] = df["2010-2015 증가율"] * 100
>>> df["2005-2010 증가율"] = ((df["2010"] - df["2005"]) / df["2005"] * 100).round(2)

>>> del df["2010-2015 증가율"]

>>> print(df)
특성   지역     2015     2010     2005     2000  2005-2010 증가율
도시
서울  수도권  9904312  9631482  9762546  9853972          -1.34
부산  경상권  3448737  3393191  3512547  3655437          -3.40
인천  수도권  2890451  2632035  2517680  2466338           4.54
대구  경상권  2466052  2431774  2456016  2473990          -0.99

 

열 인덱싱

데이터프레임은 열라벨을 키로, 열시리즈를 값으로 가지는 딕셔너리와 비슷하다. 따라서 데이터프레임을 인덱싱 할 때도 열라벨(column label)을 키 값으로 생각하여 인덱싱할 수 있다. 인덱스로 라벨 값을 하나만 넣으면 시리즈 객체가 반환되고 라벨의 배열 또는 리스트를 넣으면 부분적인 데이터프레임이 반환된다.

>>> 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, index=index, columns=columns)

>>> df.index.name = "도시"
>>> df.columns.name = "특성"

>>> print(df["지역"])
>>> print(df[["2010","2015"]])
도시
서울    수도권
부산    경상권
인천    수도권
대구    경상권
Name: 지역, dtype: object
특성     2010     2015
도시
서울  9631482  9904312
부산  3393191  3448737
인천  2632035  2890451
대구  2431774  2466052

 

행 인덱싱

만약 행 단위로 인덱싱을 하고자 하면 항상 슬라이싱(slicing)을 해야 한다. 인덱스와 같이 문자 라벨이면 라벨 슬라이싱도 가능하다.

>>> 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, index=index, columns=columns)

>>> df.index.name = "도시"
>>> df.columns.name = "특성"

>>> print(df[:1])
>>> print(df[1:2])
>>> print(df[1:3])
>>> print(df["서울":"부산"])
특성   지역     2015     2010     2005     2000  2010-2015 증가율
도시
서울  수도권  9904312  9631482  9762546  9853972         0.0283

특성   지역     2015     2010     2005     2000  2010-2015 증가율
도시
부산  경상권  3448737  3393191  3512547  3655437         0.0163

특성   지역     2015     2010     2005     2000  2010-2015 증가율
도시
부산  경상권  3448737  3393191  3512547  3655437         0.0163
인천  수도권  2890451  2632035  2517680  2466338         0.0982

특성   지역     2015     2010     2005     2000  2010-2015 증가율
도시
서울  수도권  9904312  9631482  9762546  9853972         0.0283
부산  경상권  3448737  3393191  3512547  3655437         0.0163

 

개별 데이터 인덱싱

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

>>> 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, index=index, columns=columns)

>>> df.index.name = "도시"
>>> df.columns.name = "특성"

>>> print(df["2015"]["서울"])
9904312