11. 행 삭제하기

  • 조건을 넣어 True인 값만 출력하도록 하면 조건에 맞지 않는 값은 삭제된 것과 같은 상태
import pandas as pd

df = pd.read_csv('titanic.csv')
# 데이터프레임에서 Sex열의 값이 male이 아닌 것 즉, female인 것만 출력, male은 삭제되고 female인 것만 출력됨
df[df['Sex'] != 'male'].head(2)

# 행의 인덱스를 사용해 하나의 행을 삭제할 수 있음
# 인덱스가 0인 행만 제외하고 나머지 출력
df[df.index != 0].head(2)

 

 

12. 중복된 행 삭제하기

  • drop_duplicates 사용(매개변수 사용에 주의)
# drop_duplicates를 매개변수 없이 사용하면 완벽하게 같은 행만 삭제되어 예시로 사용하는 타이타닉 데이터에서는 삭제되는 열이 없음
print('원본 데이터프레임 행의 수: {}'.format(len(df)))
print('drop_duplicates 사용한 데이터프레임 행의 수: {}'.format(len(df.drop_duplicates())))

# 출력 결과
원본 데이터프레임 행의 수: 891
drop_duplicates 사용한 데이터프레임 행의 수: 891
# 따라서 중복을 비교할 열을 subset 매개변수에 전달하여야 함
# Sex 변수에서 중복되는 값이 전부 제거되고 제일 처음 male값을 가지는 행과 female 값을 가지는 행만 남아 출력됨
df.drop_duplicates(subset = ['Sex'])

# keep 매개변수에 last를 전달하면 가장 마지막에 남은 male값과 female값만 하나씩 출력됨
df.drop_duplicates(subset = ['Sex'], keep = 'last')

 

 

13. 값에 따라 행을 그룹핑하기

  • groupby('그루핑할 열')['통계 계산을 할 열'].통계계산(mean, sum, count 등)
# 성별로 그루핑하여 각 성별의 나이 평균 계산
df.groupby('Sex')['Age'].mean()

# 출력 결과
Sex
female    27.915709
male      30.726645
Name: Age, dtype: float64

 

  • 첫 번째 열로 그루핑한 다음 두 번째 열로 다시 그룹핑하기
# 성별로 구루핑 하고 각 성별 중 생존 여부에 따라 다시 그루핑
# 이후 총 4개의 그룹 각각의 나이 평균 계산
df.groupby(['Sex', 'Survived'])['Age'].mean()

# 출력 결과
Sex     Survived
female  0           25.046875
        1           28.847716
male    0           31.618056
        1           27.276022
Name: Age, dtype: float64

 

 

14. 시간에 따라 행을 그루핑하기

  • 시간을 인덱스로 하는 예시 데이터프레임 생성
import pandas as pd
import numpy as np

# 2023/06/26부터 30초 간격으로 100,000개의 시간 데이터를 인덱스로 생성
time_index = pd.date_range('06/26/2023', periods = 100000, freq = '30s')

# 위에서 생성한 시간 인덱스를 인덱스로하고, 1~10사이의 숫자 중 랜덤하게 100,000개를 뽑은 것을 각 시간의 값으로 생성
df = pd.DataFrame(index = time_index)
df['Sale_Amount'] = np.random.randint(1, 10, 100000)

df

# 일주일 단위로 행을 그루핑
df.resample('W').sum()

  • 시간 단위
    • 'W': 1주 단위
    • '2W': 2주 단위
    • 'M': 1달 단위
    • 'MS': 1달 단위, 그루핑된 인덱스를 월의 시작 날짜로
  • label = 'left' 옵션: 인덱스를 그루핑된 그룹의 마지막 레이블이 아닌 그 전 그룹의 마지막 레이블로 변환
df.resample('M').sum()
df.resample('M', label = 'left').sum()
df.resample('MS').sum()

'M'
'M', label = 'left'
'MS'

 

 

15. 열 원소 순회하기

  • 데이터프레임의 열을 시퀀스처럼 다룰 수 있음
# 데이터프레임의 ['Name']열에 속한 값들을 하나씩 차례대로 name으로 지정하여 출력(상위 2개의 열에만 예시로 적용)
for name in df['Name'][0:2]:
    print(name.upper())

 

 

16. 모든 열 원소에 함수 적용하기

  • 데이터프레임의 특정 열의 모든 값에 동시에 함수를 적용
# 문자를 대문자로 출력하는 함수 생성
def uppercase(x):
    return x.upper()

# 위에서 생성한 함수를 데이터프레임의 'Name'열에 한번에 적용(상위 2개의 열에만 예시로 적용)
df['Name'].apply(uppercase)[0:2]

 

  • map 함수도 apply 함수와 비슷하지만 map 메서드는 딕셔너리를 입력으로 넣을 수 있고 apply 메서드는 매개변수를 지정할 수 있음
# 딕셔너리 형태로 Survived 열의 1값은 Live, 0값은 Dead로 변경
df['Survived'].map({1 : 'Live', 0 : 'Dead'})[:5]

 

  • apply 메서드에서 age라는 매개변수 전달
# age = 30이라는 매개변수 전달, Age열의 값이 전달받은 age보다 작은지에 대한 boolean 값 return
df['Age'].apply(lambda x, age: x < age, age = 30)[:5]

 

  • applymap 메서드로 전체 데이터프레임에 함수 적용 가능
# 문자값으로 이루어진 열에 대해 최대 길이를 20자로 제한하는 함수
def truncate_string(x):
    if type(x) == str:
        return x[:20]
    else:
        return x

전체 데이터프레임에 적용
df.applymap(truncate_string)[:5]

 

 

17. 그룹에 함수 적용하기

# Sex열로 그루핑하여 male 그룹과 female 그룹의 다른 열들 각각에 lambda 함수 적용
df.groupby('Sex').apply(lambda x: x.count())

 

 

18. 데이터프레임 연결하기

  • concat 함수
data_a = {'id': ['1', '2', '3'],
          'first': ['Alex', 'Amy', 'Allen'],
          'last': ['Anderson', 'Ackerman', 'Ali']}
df_a = pd.DataFrame(data_a, columns = ['id', 'first', 'last'])

data_b = {'id': ['4', '5', '6'],
          'first': ['Billy', 'Brian', 'Bran'],
          'last': ['Bonder', 'Black', 'Balwner']}
df_b = pd.DataFrame(data_b, columns = ['id', 'first', 'last'])

df_a
df_b

df_a
df_b

 

  • concat 함수에 axis = 0으로 하면 행 방향으로 데이터프레임 연결
pd.concat([df_a, df_b], axis = 0)

 

  • concat 함수에 axis = 1로 하면 열 방향으로 데이터프레임 연결
pd.concat([df_a, df_b], axis = 1)

 

 

19. 데이터프레임 병합하기

  • merge 함수
employee_data = {'employee_id': ['1', '2', '3', '4'],
                 'name': ['Amy Jones', 'Allen Keys', 'Alice Bees', 'Tim Horton']}
df_employees = pd.DataFrame(employee_data, columns = ['employee_id', 'name'])

sales_data = {'employee_id': ['3', '4', '5', '6'],
              'total_sales': [23456, 2512, 2345, 1455]}
df_sales = pd.DataFrame(sales_data, columns = ['employee_id', 'total_sales'])

df_employees
df_saeles

df_employees
df_sales

 

  • merge는 기본적으로 내부 조인을 실행(기준으로 하는 열(on = ''으로 지정한 열)이 같은 데이터만 병합하여 출력)
# 두 데이터프레임에서 employee_id가 두 곳 모두에 있는 값은 3, 4이므로 3, 4에 대해서만 다른 데이터가 병합되어 출력됨
pd.merge(df_employees, df_sales, on = 'employee_id')

 

  • how = '' 매개변수를 지정하여 outer, right, left 조인도 실행 가능
  • left, right 조인은 데이터프레임을 매개변수로 주는 순서에 따라 결과가 달라지므로 주의
pd.merge(df_employees, df_sales, on = 'employee_id', how = 'outer')

pd.merge(df_employees, df_sales, on = 'employee_id', how = 'left')

pd.merge(df_employees, df_sales, on = 'employee_id', how = 'right')

 

  • left와 right의 조인 기준열을 각각 지정할 수도 있음
pd.merge(df_employees, df_sales, left_on = 'employee_id', right_on = 'employee_id')

  • 데이터 랭글링은 원본 데이터를 정제하고 사용가능한 형태로 구성하기 위한 변환 과정을 광범위하게 의미하는 비공식 용어
  • 데이터 랭글링은 데이터 전처리의 한 과정
  • 데이터 랭글링에서 사용되는 가장 일반적인 데이터 구조는 데이터프레임

 

1. 데이터프레임 만들기

# 방법 1
import pandas as pd

df = pd.DataFrame()

df['Name'] = ['Jacky Jackson', 'Steven Stevenson']
df['Age'] = [38, 25]
df['Driver'] = [True, False]

df

# 방법 2(numpy 배열을 dataframe으로)
import numpy as np
data = [['Jacky Jackson', 38, True], ['Steven Stevencon', 25, False]]

matrix = np.array(data)
pd.DataFrame(matrix, columns = ['Name', 'Age', 'Driver'])

# or
pd.DataFrame(data, columns = ['Name', 'Age', 'Driver'])

# 방법 3(dictionary를 dataframe으로)
data = {'Name': ['Jacky Jackson', 'Steven Stevenson'],
        'Age': [38, 25],
        'Driver': [True, False]}
pd.DataFrame(data)

# 방법 4(각각의 데이터를 dictionary로, 각 dictionary를 병합)
data = [{'Name': 'Jacky Jackson', 'Age': 25, 'Driver': True},
        {'Name': 'Steven Stevenson', 'Age': 38, 'Driver': False}]
# 인덱스 따로 지정 가능
pd.DataFrame(data, index = ['row1', 'row2'])

 

 

2. 데이터 설명하기

  • 데이터를 적재한 후 확인하는 가장 간단한 방법은 head()를 통해 상위 몇 개의 데이터만 출력해서 확인해보는 것
  • tail()을 사용하면 하위 데이터 출력
df = pd.read_csv('titanic.csv')

# 데이터의 상위 2행만 출력
df.head(2)

 

  • 데이터의 열과 행의 개수 확인
df.shape

# 출력 결과
(891, 12)

 

  • describe()를 사용하여 숫자데이터 열의 통계값 확인
df.describe()

 

 

3. 데이터프레임 탐색하기

  • loc 또는 iloc를 사용해 하나 이상의 행이나 값을 선택
  • loc와 iloc 슬라이싱은 numpy와 달리 마지막 인덱스를 포함
# 첫번째 행 출력
df.iloc[0]

# 출력 결과
PassengerId                          1
Survived                             0
Pclass                               3
Name           Braund, Mr. Owen Harris
Sex                               male
Age                               22.0
SibSp                                1
Parch                                0
Ticket                       A/5 21171
Fare                              7.25
Cabin                              NaN
Embarked                             S
Name: 0, dtype: object
# 콜론(:)을 사용하여 행 슬라이싱
# 첫번째 행부터 네번째 행까지 출력
df.iloc[1:4]

# 슬라이싱의 첫 부분을 공백으로 두면 처음부터 선택
# 슬라이싱의 마지막 부분을 공백으로 두면 마지막까지 선택
df.iloc[:4]

# 데이터프레임에서 행마다 고유한 값을 갖는 특정 열을 인덱스로 설정
# loc를 사용해 고유값으로 해당 행을 슬라이싱 가능
df_name_index = df.set_index(df['Name'])
df_name_index.loc['Braund, Mr. Owen Harris']

# 출력 결과
PassengerId                          1
Survived                             0
Pclass                               3
Name           Braund, Mr. Owen Harris
Sex                               male
Age                               22.0
SibSp                                1
Parch                                0
Ticket                       A/5 21171
Fare                              7.25
Cabin                              NaN
Embarked                             S
Name: Braund, Mr. Owen Harris, dtype: object
# 열을 선택하여 선택한 열만 출력하기도 가능
df[['Age', 'Sex']].head(2)

 

 

4. 조건에 따라 행 선택하기

# 데이터프레임 df[] 안에 조건문인 df['Sex'] == female을 넣어서 True인 행만 출력
df[df['Sex'] == 'female'].head(2)

# &를 사용해 조건 두 개이상도 검색 가능
df[(df['Sex'] == 'female') & (df['Age'] >= 60)].head(2)

 

 

5. 값 치환하기

df['Sex'].replace('female', 'woman').head(2)

# 출력 결과
0     male
1    woman
Name: Sex, dtype: object


# 두 개 이상도 한번에 치환 가능
df['Sex'].replace(['female', 'male'], ['woman', 'man']).head(5)

# 출력 결과
0      man
1    woman
2    woman
3    woman
4      man
Name: Sex, dtype: object


# 한번에 여러 값은 하나의 값으로 치환 가능
df['Sex'].replace(['female', 'male'], 'person').head(5)

# 출력 결과
0    person
1    person
2    person
3    person
4    person
Name: Sex, dtype: object


# 치환할 여러 값을 딕셔너리 형태로 전달 가능
df['Sex'].replace({'female' : 1, 'male' : 0}).head(5)

# 출력 결과
0    0
1    1
2    1
3    1
4    0
Name: Sex, dtype: int64
# 위에서 하나의 열뿐 아니라 데이터프레임 전체의 모든 값을 한번에 치환 가능
df.replace(1, 'one').head(2)

 

 

6. 열 이름 바꾸기

df.rename(columns = {'Pclass' : 'Passenger Class'}).head(2)

 

  • 전체 열 이름을 바꿀 때 열이 많아 각각 입력하기 힘들다면 열 이름은 키로, 값은 비어있는 딕셔너리로 만들어 비어있는 값에 바꿀 열 이름을 넣어서 rename()에 전달하면 편리함
import collections

column_names = collections.defaultdict(str)

for name in df.columns:
    column_names[name]

column_names

# 출력 결과
defaultdict(str,
            {'PassengerId': '',
             'Survived': '',
             'Pclass': '',
             'Name': '',
             'Sex': '',
             'Age': '',
             'SibSp': '',
             'Parch': '',
             'Ticket': '',
             'Fare': '',
             'Cabin': '',
             'Embarked': ''})

 

  • rename(columns = {}) 대신 rename(index = {})으로 인덱스 치환가능
df.rename(index = {0:-1}).head(2)

 

  • 열 이름 소문자로 바꾸기
# 변환 함수 전달
df.rename(str.lower, axis = 'columns').head(2)

 

 

7. 최소값, 최대값, 합, 평균 계산 및 개수 세기

  • 각 통계값에 맞는 메서드 사용
    • 최대값: max()
    • 최소값: min()
    • 평균: mean()
    • 합: sum()
    • 개수: count()
    • 분산: var()
    • 표준편차: std()
    • 첨도: kurt()
    • 왜도: skew()
    • 평균의 표준오차: sem()
    • 최빈값: mode()
    • 중간값: median()
    • 상관계수: corr()
    • 공분산: cov()
print('최대값:', df['Age'].max())
print('최th값:', df['Age'].min())
print('평균:', df['Age'].mean())
print('합:', df['Age'].sum())
print('카운트:', df['Age'].count())

# 출력 결과
최대값: 80.0
최th값: 0.42
평균: 29.69911764705882
합: 21205.17
카운트: 714

 

  • 데이터프레임 전체에도 적용 가능
df.count()

# 출력 결과
PassengerId    891
Survived       891
Pclass         891
Name           891
Sex            891
Age            714
SibSp          891
Parch          891
Ticket         891
Fare           891
Cabin          204
Embarked       889
dtype: int64

 

 

8. 고유값 찾기

  • unique 메서드를 사용해 열에서 고유한 값을 모두 찾음
df['Sex'].unique()

# 출력 결과
array(['male', 'female'], dtype=object)

 

  • nunique 메서드는 unique 값의 개수를 출력
df['Sex'].nunique()

# 출력 결과
2


# nunique는 데이터프레임 전체에 적용 가능
df.nunique()

# 출력 결과
PassengerId    891
Survived         2
Pclass           3
Name           891
Sex              2
Age             88
SibSp            7
Parch            7
Ticket         681
Fare           248
Cabin          147
Embarked         3
dtype: int64

 

  • value_counts() 메서드를 사용해 열에서 고유한 값 각각의 개수 출력
df['Sex'].value_counts()

# 출력 결과
Sex
male      577
female    314
Name: count, dtype: int64

 

 

9. 누락된 값 다루기

  •  isnull()과 notnull() 메서드는 null인지 아닌지에 대한 답을 boolean값(True나 False)으로 나타냄
# 조건으로 isnull()을 주어 True나 False의 값이 나오므로 True인 행만 찾아 출력 가능
df[df['Age'].isnull()].head()

 

  • read_csv() 메서드에서 na_values = [] 옵션을 사용해 null 값으로 선언할 값들은 지정
  • read_csv() 메서드에서 keep_default_na 옵션을 False로 하여 pandas에서 기본적으로 null 값으로 인식하는 값을을 null값이 아니게 만들 수 있음
  • read_csv() 메서드에서 na_filter 옵션을 False로 하면 NaN 변환을 하지 않음

 

 

10. 열 삭제하기

  • drop() 메서드 사용
# 축은 열을 나타내는 1로 지정
df.drop('Age', axis = 1)

 

  • 한 번에 여러개의 열 삭제 가능
df.drop(['Age', 'Sex'], axis = 1)

 

  • 열 이름이 없다면 열의 인덱스 번호를 사용해 삭제 가능
# 인덱스가 1인 열(두번째 열) 삭제
df.drop(df.columns[1], axis = 1)

 

  • del df['Age']를 사용해 열을 삭제할 수 있지만 이는 원보 데이터프레임을 바꿔 원본 데이터의 손상을 유발할 수 있어 추천 X
  • inplace = True 옵션을 사용해도 원본 데이터가 변형되므로 사용 X
  • 또는, 원본 데이터는 놔두고 데이터를 조작할 새로운 데이터프레임을 복사하여 만들면 좋음
  • 머신러닝을 위한 원본 데이터는 로그 파일이나 데이터셋 파일, 데이터베이스, 여러 소스에서 추출
  • CSV, SQL 데이터베이스 등 다양한 소스에서 데이터를 적재하는 방법 학습
  • 실험에 필요한 특성을 가진 모의 데이터 생성 방법 학습
  • 외부 데이터 적재에는 판다스 / 모의 데이터 생성에는 사이킷런 사용

1. 샘플 데이터셋 적재하기

  • 사이킷런의 예제 데이터 사용
# pip install scikit-learn
from sklearn import datasets

# 숫자 데이터셋 적재
digits = datasets.load_digits()

# 특성 행렬
features = digits.data

# 타깃 벡터 생성
target = digits.target

# 첫번째 샘플 확인
features[0]

# 출력 결과
array([ 0.,  0.,  5., 13.,  9.,  1.,  0.,  0.,  0.,  0., 13., 15., 10.,
       15.,  5.,  0.,  0.,  3., 15.,  2.,  0., 11.,  8.,  0.,  0.,  4.,
       12.,  0.,  0.,  8.,  8.,  0.,  0.,  5.,  8.,  0.,  0.,  9.,  8.,
        0.,  0.,  4., 11.,  0.,  1., 12.,  7.,  0.,  0.,  2., 14.,  5.,
       10., 12.,  0.,  0.,  0.,  0.,  6., 13., 10.,  0.,  0.,  0.])

 

  • 사이킷런 예제 데이터들은 딕셔너리 구조를 가지고 있어 keays와 values를 반환함
digits.keys()

# 출력 결과
dict_keys(['data', 'target', 'frame', 'feature_names', 'target_names', 'images', 'DESCR'])


# DESCR 키는 데이터셋에 대한 설명
print(digits['DESCR'])

# 출력 결과
.. _digits_dataset:

Optical recognition of handwritten digits dataset
--------------------------------------------------

**Data Set Characteristics:**

    :Number of Instances: 1797
    :Number of Attributes: 64
    :Attribute Information: 8x8 image of integer pixels in the range 0..16.
    :Missing Attribute Values: None
    :Creator: E. Alpaydin (alpaydin '@' boun.edu.tr)
    :Date: July; 1998

This is a copy of the test set of the UCI ML hand-written digits datasets
https://archive.ics.uci.edu/ml/datasets/Optical+Recognition+of+Handwritten+Digits

The data set contains images of hand-written digits: 10 classes where
each class refers to a digit.

Preprocessing programs made available by NIST were used to extract
normalized bitmaps of handwritten digits from a preprinted form. From a
total of 43 people, 30 contributed to the training set and different 13
to the test set. 32x32 bitmaps are divided into nonoverlapping blocks of
4x4 and the number of on pixels are counted in each block. This generates
...
    2005.
  - Claudio Gentile. A New Approximate Maximal Margin Classification
    Algorithm. NIPS. 2000.

 

  • load_데이터셋의 유일한 매개변수인 return_X_y를 True로 하면 특성 X와 타깃 y배열을 반환
import numpy as np

# digits 함수는 특별히 n_class 매개변수를 사용하여 필요한 숫자 개수 지정가능
# 0~4까지 5개의 숫자만 y값에 넣도록 매개변수 설정
X, y = datasets.load_digits(n_class = 5, return_X_y = True)

np.unique(y)
# 출력 결과
array([0, 1, 2, 3, 4])

 

 

2. 모의 데이터셋 만들기

  • 선형 회귀 알고리즘에 사용하려면 make_regression 추천
  • make_regression은 실수 특성 행렬과 실수 타깃 벡터 반환
from sklearn.datasets import make_regression

# n_features는 전체 특성
# n_informative는 타깃 벡터 생성에 사용할 특성
features, target, coefiicients = make_regression(n_samples = 100,
                                                 n_features = 3,
                                                 n_informative = 3,
                                                 n_targets = 1,
                                                 noise = 0.0,
                                                 coef = True,
                                                 random_state = 1)
from sklearn.datasets import make_regression
features, target, coefiicients = make_regression(n_samples = 100,
                                                 n_features = 3,
                                                 n_informative = 3,
                                                 n_targets = 1,
                                                 noise = 0.0,
                                                 coef = True,
                                                 random_state = 1)
print('특성 행렬\n', features[:3])
print('타깃 벡터\n', target[:3])

# 출력 결과
특성 행렬
 [[ 1.29322588 -0.61736206 -0.11044703]
 [-2.793085    0.36633201  1.93752881]
 [ 0.80186103 -0.18656977  0.0465673 ]]
타깃 벡터
 [-10.37865986  25.5124503   19.67705609]

 

  • 분류 알고리즘에 사용하려면 make_classification 추천
  • make_classification은 실수 특성 행렬과 정수 타깃 벡터 반환
from sklearn.datasets import make_classification
# n_redundant는 필요없는 특성의 수, n_informative 특성의 랜덤 선형 결합으로 생성됨
# weights는 차례대로 각각 첫번째 ,두번째 클래스의 비율
features, target = make_classification(n_samples = 100,
                                                     n_features = 3,
                                                     n_informative = 3,
                                                     n_redundant = 0,
                                                     n_classes = 2,
                                                     weights = [.25, .75],
                                                     random_state = 1)
print('특성 행렬\n', features[:3])
print('타깃 벡터\n', target[:3])

# 출력 결과
특성 행렬
 [[ 1.06354768 -1.42632219  1.02163151]
 [ 0.23156977  1.49535261  0.33251578]
 [ 0.15972951  0.83533515 -0.40869554]]
타깃 벡터
 [1 0 0]

 

  • 군집 알고리즘에 사용하려면 make_blobs 추천
  • make_blobs은 실수 특성 행렬과 정수 타깃 벡터 반환
from sklearn.datasets import make_blobs
features, target = make_blobs(n_samples = 100,
                                       n_features = 2,
                                       centers = 3,
                                       cluster_std = 0.5,
                                       shuffle = True,
                                       random_state = 1)
print('특성 행렬\n', features[:3])
print('타깃 벡터\n', target[:3])

# 출력 결과
특성 행렬
 [[ -1.22685609   3.25572052]
 [ -9.57463218  -4.38310652]
 [-10.71976941  -4.20558148]]
타깃 벡터
 [0 1 1]
# 만들어진 군집 데이터 시각화
# pip install matplotlib
import matplotlib.pyplot as plt

plt.scatter(features[:, 0], features[:, 1], c = target)
plt.show()

 

 

3. CSV 파일 적재하기

  • pandas 라이브러리의 read_csv() 사용
  • 매개변수
    • sep = ',': 파일이 사용하는 구분자를 ','로 지정
    • skiprows = range(1, 11): 1행부터 12행까지 건너뛴 후 출력
    • nrows = 1: 한 행 출력
import pandas as pd

dataframe = pd.read_csv('csv 경로')

 

 

4. 엑셀 파일 적재하기

  • pandas 라이브러리의 read_excel() 사용
  • read_excel()을 사용하려면 xlrd 패키지 설치 필요
  • 매개변수
    • sheet_name: 시트 이름 문자열 또는 시트의 위치를 나타내는 정수(0부터 시작되는 인덱스)
    • na_filter: 결측값 탐지, 결측값이 없는 데이터라면 해당 옵션을 제외하는 것이 성능 향상에 도움
    • skip_rows
    • nrows
    • keep_default_na: 공백을 NA로 지정할지 결정
    • na_values = '-': 결측값을 '-'로 표시
# pip install xlrd
import pandas as pd

dataframe = pd.read_excel('excel 경로')

 

 

5. JSON 파일 적재하기

  • pandas 라이브러리의 read_json() 사용
  • 매개변수
    • orient = 'columns'(split, records, index, columns, values 중 하나): JSON 파일의 구성 형식 지정, 어떤 값을 넣어야하는 지 알아내기 위해서는 실험이 필요
      • 'split': {"index" : [인덱스, ...], "columns" : [열, ...], "data" : [값, ...]}
      • 'records': {[열 : 값}, ..., {열 : 값}]
      • 'index': {인덱스 : {열 : 값, ...}, ...}
      • 'values': [값, ...]
      • 'columns': {열: {인덱스 : 값, ...}, ...}
    • json_normalize: 구조화가 덜 된 JSON 데이터를 데이터프레임으로 변환하는 도구
import pandas as pd

dataframe = pd.read_json('json 경로', orient = 'columns')

 

 

6. SQL 데이터베이스로부터 적재하기

  • pandas 라이브러리의 read_sql_query() 사용
  • 먼저, SQLite 데이터베이스 엔진으로 연결하기 위해 create_engine 함수 사용
  • 이후, read_sql_query 함수로 SQL을 사용하여 데이터베이스에 질의, 그 결과를 데이터프레임으로 가져옴
# pip install sqlalchemy
import pandas as pd
from sqlalchemy import create_engine

# sample.db라는 데이터베이스에 연결
database_connection = create_engine('sqlite:///sample.db')

# sample.db에서 data라는 이름의 테이블의 모든 열을 반환하라고 요청
dataframe = pd.read_sql_query('SELECT * FROM data', database_connection)

# 모든 행을 가져올 때는 질의문 없이 read_sql_table() 함수도 사용 가능
dataframe = pd.read_sql_table('data', database_connection)

2-10. 고윳값과 고유벡터 찾기

고유벡터: 정방 행렬 A를 선형 변환으로 봤을 때, 선형 변환 A에 의한 변환 결과가 자기 자신의 상수 배가 되는 0이 아닌 벡터

고유값: 이때의 상수배 값

Av: v라는 열 벡터에 선형 변환 A를 해주었다

Av = λv: v라는 열 벡터에 선형 변환 A를 해준 결과가 열 벡터v의 상수 배(λ)와동일

               즉, 벡터 v에 대해 선형 변환 A를 해주었을 때, 벡터 v의 방향은 변하지 않고 크기만 변함

그림 1) 출처: 공돌이의 수학정리노트 유튜브
그림 2) 출처: 공돌이의 수학정리노트 유튜브

그림 2)는 그림 1)을 선형변환한 것

파란색 화살표는 크기는 변했지만 방향은 그대로이므로 변한 크기 비율인 λ를 고유값으로하는 고유벡터

분홍색 화살표도 방향은 그대로이며 크기도 그대로이므로 λ=1인 고유벡터

빨간색 화살표는 방향과 크기가 모두 변했으므로 고유벡터가 아님

 

 

고유벡터의 성질로 det(A - λI)=0이어야하며 이를 이용해 고유값과 고유벡터를 구할 수 있음

A는 주어진 행렬

λ는 구해야하는 고유값

I는 A와 같은 크기의 단위행렬

행렬식을 이용해 λ를 구하면 Av = λv식에 λ를 대입하여 v 구하기

 

파이썬에서는 linalg.eig 함수 사용

import numpy as np

matrix=np.array([[1, -1, 3],
                          [1, 1, 6],
                          [3, 8, 9]])

eigenvalues, eigenvectors=np.linalg.eig(matrix)
print('고유값: ', eigenvalues)
print('고유벡터: ', eigenvectors)

### 결과 ###
고유값: array([13.55075847, 0.74003145, -3.29078992])
고유벡터: array([[-0.17511017, -0.96677403, -0.53373322],
                        [-0.435951  , 0.2053623  , -0.64324848],
                        [-0.88254925, 0.15223105 , 0.54896288]])

대칭행렬일 경우 np.linalg.eigh(matrix)를 사용하면 더 빨리 계산(대칭행렬 여부를 확인하지는 않음)

 

 

 

2-11. 점곱 계산하기

점곱은 행렬의 같은 위치의 성분끼리 곱해준 것

import numpy as np

vector_a=np.array([1,2,3])
vector_b=np.array([4,5,6])

np.dot(vector_a,vector_b)

### 결과 ###
32


# np.dot 대산에 @를 사용할 수도 있음
vector_a @ vector_b

### 결과 ###
32

vector_a와 vector_b의 점곱은 1×4 + 2×5 + 3×6=32

 

 

 

2-12. 행렬 곱셈

행렬의 곱셈

첫번째 행렬 첫번째 행 × 두번째 행렬 첫번째 열      첫번째 행렬 첫번째 행 × 두번째 행렬 두번째 열

첫번째 행렬 두번째 행 × 두번째 행렬 첫번째 열      첫번째 행렬 두번째 행 × 두번째 행렬 두번째 열

 

파이썬에서는 np.dot사용

import numpy as np

matrix_a=np.array([[1,1],
                              [1,2]])

matrix_b=np.array([[1,3],
                              [1,2]])

np.dot(matrix_a,matrix_b)

### 결과 ###
array([[2,5],
          [3,7]])


# np.dot 대신에 @ 사용 가능
matrix_a @ matrix_b

### 결과 ###
array([[2,5],
          [3,7]])


# 원소별 곱셈을 하려면 * 사용
matrix_a * matrix_b

### 결과 ###
array([[1,3],
          [1,4]])

 

 

※ np.dot과 np.matmul의 차이

 -(a,b,c,D) 크기의 4차원 배열은 c행 D열의 행렬 b개의 있는 행렬이 a개 있는 행렬

 -(e,f,D,h)크기의 4차원 배열은 D행 h열의 행렬 f개 있는 행렬이 e개 있는 행렬

 -np.dot은 (a,b,c,D) 크기의 배열과 (e,f,D,h) 크기의 배열의 곱셈의 결과로 (a,b,c,e,f,h)크기의 배열을 만듦

 -@(np.matmul)는 (a,b,c,D) 크기의 배열과 (e,f,D,h) 크기의 배열의 곱셈의 결과로 (a',b',c,h)크기의 배열을 만듦

    →a와 e는 같거나 둘 중 하나는 1, b와 f는 같거나 둘 중 하나는 1이어야 함

    →a'와 b'는 각각 a와 e, b와 f 중 1이 아닌 값

 

 

 

2-13. 역행렬

정방행렬의 역행렬은 정방행렬과 곱했을 때 단위행렬 I가 되는 행렬

파이썬에서는 np.linalg.inv 사용

import numpy as np
matrix=np.array([[1,4],
                          [2,5]])

np.linalg.inv(matrix)

### 결과 ###
array([[-1.66666667,  1.33333333],
          [ 0.66666667, -0.33333333]])


# 행렬과 역행렬을 곱하면 대각원소가 전부 1이고 나머지 원소는 0인 단위행렬이 나옴
matrix @ np.linalg.inv(matrix)

### 결과 ###
array([[1., 0.],
          [0., 1.]])

 

정방행렬이 아닌 행렬의 역행렬을 유사 역행렬이라고 부르며 계산할 수 있음, np.linalg.pinv() 사용

import numpy as np

matrix=np.array([[1,4,7],
                          [2,5,8]])

np.linalg.pinv(matrix)

### 결과 ###
array([[-1.6666667,  1.],
          [-0.3333333,  0.3333333],
          [ 0.5      , -0.3333333]])

'Python > 기본문법' 카테고리의 다른 글

데이터 랭글링 (2)  (0) 2023.06.26
데이터 랭글링 (1)  (0) 2023.06.23
데이터 적재  (0) 2023.06.22
Numpy로 배열, 벡터, 행렬 이해하기 (2)  (0) 2022.10.19
Numpy로 배열, 벡터, 행렬 이해하기 (1)  (0) 2022.10.17

2-5. 행렬 전치

행렬의 전치: 행과 열의 인덱스를 바꿈(1열→1행, 2열→2행, ..., 1행→1열, 2행→2열, ...), T 또는 transpose() 사용

import numpy as np
matrix=np.array([[1,2,3],
                          [4,5,6],
                          [7,8,9]])

# 행렬 전치
matrix.T

### 결과 ###
array([[1,4,7],
          [2,5,8],
          [3,6,9]])

 

벡터의 전치는 행벡터를 열벡터로 또는 열벡터를 행벡터로 바꾸는 것

벡터는 값의 모음이기 때문에 원래 기술적으로 전치할 수 없지만 대괄호를 두번 사용하면 전치 가능

matrix=np.array([[1,2,3,4,5,6]])

matrix.T

### 결과 ###
array([[1],
       [2],
       [3],
       [4],
       [5],
       [6]])

 

 

T 대신 transpose() 사용가능, transpose((차원의 튜플))을 통해 바꿀 차원을 직접 지정도 가능

# transpose() 사용
matrix=np.array([[1,2,3],
                          [4,5,6],
                          [7,8,9]])

# 행렬 전치
matrix.transpose()

### 결과 ###
array([[1,4,7],
          [2,5,8],
          [3,6,9]])


# transpose((차원 튜플)) 사용
matrix=np.array([[[1,2],
                            [3,4],
                            [5,6]],
                  
                           [[7,8],
                            [9,10],
                            [11,12]]])

matrix.transpose((0,2,1))

### 결과 ###
array([[[1,3,5],
            [2,4,6]],
           [[7,9,11],
            [8,10,12]]])

2×3×2 행렬을 transpose((0,2,1))을 적용하면 2×2×3 행렬로 전치됨, (0,2,1)은 차원의 순서를 나타내는 것으로 원래 차원의 (첫번째 숫자. 세번째 숫자, 두번째 숫자)를 의미

 

 

2-6. 행렬 펼치기

행렬을 1차원 배열로 펼치기, flatten()사용

matrix=np.array([[1,2,3],
                          [4,5,6],
                          [7,8,9]])

# 행렬 펼치기
matrix.flatten()

### 결과 ###
array([1,2,3,4,5,6,7,8,9])



# reshape() 사용으로도 똑같은 결과를 만들 수 있음
matrix.reshape(1,-1)

### 결과 ###
array([1,2,3,4,5,6,7,8,9])

reshape()는 원본의 뷰를 반환하여 원본의 값을 바꾸면 reshape()로 바꾼 배열의 값도 바뀜

flatten()은 새로운 배열을 만드는 것이므로 원본의 값을 바꿔도 값이 바뀌지 않음

 

 

 

2-7. 행렬의 랭크

행렬의 차원 수를 뜻함

 

 

 

2-8. 행렬식 계산

행렬식은 행렬을 대표하는 값으로 다음과 같이 계산

 

2×2 행렬의 행렬식

 

3×3 행렬의 행렬식

 

파이썬에서는 numpy의 선형대수 메서드 det 사용

import numpy as np
matrix=np.array([[1,5,0],
                          [2,4,-1],
                          [0,-2,0]])

# 행렬식 계산
np.linalg.det(matrix)

### 결과 ###
-1.9999999999999998

 

 

 

2-9. 행렬의 대각원소

정방행렬에서 대각선에 위치한 원소(1행1열, 2행2열, 3행3열...에 해당하는 원소), diagnoal() 사용

import numpy as np
matrix=np.array([[1,2,3],
                          [2,4,6],
                          [3,8,9]])

# 행렬의 대각원소 반환
matrix.diagonal()

### 결과 ###
array([1,4,9])

offset 매개변수를 이용하면 대각원소 하나 위 또는 아나 아래의 원소를 반환

matrix=np.array([[1,2,3],
                          [2,4,6],
                          [3,8,9]])

# 행렬의 대각원소 하나 위의 원소 반환
matrix.diagonal(offset=1)

### 결과 ###
array([2,6])


# 행렬의 대각원소 하나 아래의 원소 반환
matrix.diagonal(offset=-1)

### 결과 ###
array([2,8])

 

 

np.diag()에서 ()에 1차원 배열을 넣으면 1차원 배열을 대각원소로 하는 2차원 대각행렬을 생성

a=np.diagonal(matrix)
print(a)

### 결과 ###
array([1,4,9])


# 1차원 배열의 대각원소 사용하여 2차원 대각행렬 만들기
np.diag(a)

### 결과 ###
array([[1,0,0],
          [0,4,0],
          [0,0,9]])

 

 

trace()를 사용하여 대각원소의 합인 대각합 계산

matrix=np.array([[1,2,3],
                          [2,4,6],
                          [3,8,9]])

matrix.traace()

### 결과 ###
14
# matrix의 대각원소는 [1,4,9]이므로 1+4+9=14

'Python > 기본문법' 카테고리의 다른 글

데이터 랭글링 (2)  (0) 2023.06.26
데이터 랭글링 (1)  (0) 2023.06.23
데이터 적재  (0) 2023.06.22
Numpy로 배열, 벡터, 행렬 이해하기 (3)  (0) 2022.10.20
Numpy로 배열, 벡터, 행렬 이해하기 (1)  (0) 2022.10.17

1. 벡터

1-1. 벡터는 1행 또는 1열로 이루어진 1차원 배열

import numpy as np

vector_row=np.array([1,2,3])    # 1행으로 이루어진 행벡터
vector_column=np.array([[1],    # 1열로 이루어진 열벡터
                        [2],
                        [3]])

 

1-2. asarray함수를 사용하여 배열을 만들수 있음

import numpy as np

new_row=np.asarray([1,2,3])    # np.array와 똑같이 1행으로 이루어진 행벡터 생성

 

np.asarray(넘파이 배열)은 새로운 배열 생성X

np.array(넘파이 배열)은 새로운 배열 생성

# array 사용

vector_row=np.array([1,2,3])    # 1행으로 이루어진 행벡터
new_row=np.array(vector_row)    # array의 copy 매개변수는 배열을 복사할지 선택, 
                                # 기본값은 True이므로 new_row에는 vector_row의 복사본 저장
                                
new_row[0]=10   # new_row의 첫번째 값 변경
print('new_row:',new_row)
print('vector_row:',vector_row)

### 결과 ###
new_row: [10,2,3]     # 복사본인 자기 자신에게만 영향을 주고
vector_row: [1,2,3]   # 원래 배열에는 영향을 주지 않음


# asarray 사용

new_row=np.asarray(vector_row)    # asarray는 새로운 배열을 생성하지 않고 원래의 배열 그 자체가 됨

new_row[0]=10   # new_row의 첫번째 값 변경
print('new_row:',new_row)
print('vector_row:',vector_row)

### 결과 ###
new_row: [10,2,3]      # 자기 자신에게 영향을 주고
vector_row: [10,2,3]   # 원래 배열에도 똑같이 영향을 줌

 

 

 

2. 행렬

2-1. 1개 이상의 행과 열로 이루어진 2차원 배열

import numpy as np

matrix=np.array([[1,2],    # 3행 2열의 행렬
                 [1,2],
                 [1,2]])

matrix_object=np.mat([[1,2],    # 3행 2열의 행렬, numpy의 행렬에 특화된 데이터 구조
                      [1,2],
                      [1,2]])

np.array()를 사용해 행렬 생성

np.mat가 행렬에 특화되어 있긴 하지만

   -numpy의 표준 데이터 구조는 배열이고

   -대부분의 넘파이 함수는 행렬 객체가 아닌 배열을 반환하므로

np.mat()보다는 np.array()를 사용

 

 

2-2. 희소행렬

데이터에서 0이 아닌 값이 매우 적을 때 이 데이터를 효율적으로 표현하는 방법

0이 아닌 값의 행과 열의 번호와 그 값만 저장됨

import numpy as np
from scipy import sparse

matrix=np.array([[0,0],
                 [0,1],
                 [3,0]])

matrix_sparse=sparse.csr_matrix(matrix)
print(matrix_sparse)

### 결과 ###
(1,1) 1    # 두번째 행, 두번째 열의 값 1
(2,0) 3    # 세번째 행, 첫번째 열의 값 3

위에서 사용한 것은 CSR(Compressed Sparse Row)이고

이외에도 CSC(Compressed Sparse Column), 리스트의 리스트, 키의 딕셔너리 등 여러 종류의 희소 행렬이 존재

가장 좋은 희소 행렬은 없고 각 희소 행렬 사이의 유의미한 차이를 통해 어떤 것을 적용하면 좋을 지 결정

    -키의 딕셔너리(Dictionary of Keys, DOK): 행렬에서 0이 아닌 값의 (행번호, 열번호)를 키, 행렬값을 값으로 하는 딕셔너리

    -리스트의 리스트(List of lists, LIL): 링크드 리스트 알고리즘 이용하여 추가와 삭제가 용이하지만 CSR과 CSC에 비해 메모리 낭비

    -좌표 리스트(Coordinate list, COO): (행, 열, 값)의 튜플로 저장, 임의 엑세스 시간을 향상시키기 위해 행 인덱스→열 인덱스 순으로 정렬 가능, 점진적 행렬 구성에 유용

    -CSR: 가로 순서대로 재정렬(행에 관해 정리 압축)

        →데이터(A): 0이 아닌 행렬 값과 값의 (행 번호, 열 번호)가 저장

        →열 인덱스 값(JA): 0행에서 값이 있는 열은 0, 3

                                          1행에서 값이 있는 열은 2, 4

                                          2행에서 값이 있는 열은 1

                                          3행에서 값이 있는 열은 2, 4

        →행 압축 정보(IA): (최초 시작행 번호, 시작행에 있는 데이터 개수, 두번째 행까지 데이터 누적 개수,..., 마지막행까지 데이터 누적 개수)

 

    -CSC: 열에 관해 정렬한 것, CSR과 저장 알고리즘은 동일, LIL에 비해 저장 메모리 70% 이상 줄일 수 있지만 추가와 삭제가 용이하지 않음

 

# toarray
print(matrix_sparse.toarray())

### 결과 ###
[[0,0],
 [0,1],
 [3,0]]    # 희소 행렬을 다시 밀집 배열로 변환
 
 
 # todense
 print(matrix_sparse.todense())
 
 ### 결과 ###
 matrix([[0,0],
         [0,1],
         [3,0]])    # 희소 행렬을 np.matrix 객체로 변환

 

 

2-3. 벡터화 연산

배열의 여러 원소에 어떤 함수 적용하기

import numpy as np

matrix=np.array([[1,2,3],
                 [4,5,6],
                 [7,8,9]])

# 100을 더하는 함수
add_100=lambda i:i+100

# 함수를 np.vectorize(함수)를 통해 벡터화 시킴
vectorized_add_100=np.vectorize(add_100)

# 행렬에 벡터화된 함수를 적용시키면 행렬의 모든 원소에 함수 적용
vectorized_add_100(matrix)

### 결과 ###
array([[101,102,103],
       [104,105,106],
       [107,108,109]])

벡터화 연산은 기본적으로 for 루프를 구현한 것이므로 성능이 향상되지는 않음

 

 

2-4. 브로드캐스팅

넘파이 배열이 차원이 달라도 배열간 연산을 수행할 수  있음을 이용한 브로드캐스팅을 사용하면 더 간단하게 배열의 각 원소에 연산 적용 가능

# 1. 모든 원소에 100을 더함
matrix+100

### 결과 ###
array([[101,102,103],
       [104,105,106],
       [107,108,109]])


# 2. 행을 따라 더해짐
matrix+[100,100,10]

### 결과 ###
array([[101,102,13],
       [104,105,16],
       [107,108,19]])


# 3. 열을 따라 더해짐
matrix+[[100],[100],[10]]

### 결과 ###
array([[101,102,103],
       [104,105,106],
       [17,18,19]])

 

'Python > 기본문법' 카테고리의 다른 글

데이터 랭글링 (2)  (0) 2023.06.26
데이터 랭글링 (1)  (0) 2023.06.23
데이터 적재  (0) 2023.06.22
Numpy로 배열, 벡터, 행렬 이해하기 (3)  (0) 2022.10.20
Numpy로 배열, 벡터, 행렬 이해하기 (2)  (0) 2022.10.19

+ Recent posts