<jupyter_start><jupyter_text>Fastcampus 파이썬 전처리 - 1-2. 파이썬 주요 데이터 구조- toc: true- badges: false- comments: true- author: <NAME>- categories: [ ___  B. MACHINE LEARNING ___ > Pre-processing] - - -- - - 리스트와 튜플_[공통점]_- 인덱싱과 슬라이싱 가능- iterable_[차이점]_- __리스트는 가변, 튜플은 불변__ 이므로 리스트는 사전의 key로 사용할 수 없고 튜플은 가능하다. - 순회 속도는 리스트보다 __튜플이 약간 더 빠르다__ (따라서 요소 변경이 필요없는 경우 튜플이 적합) - - - 리스트 관련 함수<jupyter_code>list1 = [5, 6, 7, 8, 9, 10]

## 요소 추가
# .append(x) => 새로운 요소x를 맨 뒤에 추가
list1.append(10)
print(list1)
list1.append(20)
print(list1)

# .insert(a, x) => 새로운 요소 x를 a 위치에 추가 (기존의 요소는 뒤로 밀림)
list1.insert(1,15)
print(list1)

## 요소 제거
# .remove(x) => 기존 요소 x를 제거 (단, x가 여러 개면 맨 앞 하나만 지워지고, 없으면 오류 발생)
list1.remove(10)
print(list1)

# .pop() => 맨 마지막 요소를 출력하면서 그 요소를 삭제 (stack 구조)
list1.pop()

## 위치 찾기
# .index(x) => x의 위치를 반환 (단, x가 여러 개면 맨 앞 인덱스를 반환하고, 없으면 오류 발생)
list1.index(7)<jupyter_output><empty_output><jupyter_text>- - - 튜플 관련 함수- 소괄호를 쓰지 않아도 된다는 특징 덕분에 SWAP (값을 서로 변경), 함수의 가변인자 및 여러개의 출력을 받는데 많이 사용<jupyter_code># 소괄호 없이 튜플 만들기
T = 1, 2, 3
print(T)

# 원소가 하나인 튜플은 반드시 원소뒤에 쉼표 붙여서 표시
T = 1,
print(type(T))
print(T)

# 튜플을 이용한 여러 값 동시에 입력 받기 및 SWAP
a, b = 1, 2
print(a, b)
b, a = a, b
print(a, b)

# 함수의 가변인자로 사용
def f(*x):
	print("입력된 데이터 타입 {}".format(type(x)))
	sum_x = 0
	product_x = 1
	for val in x:  # x는 튜플이므로 iterable => for문 사용가능
		sum_x += val
		product_x *= val
	return sum_x, product_x

S, P = f(1,2,3,4,5)
print(S, P)<jupyter_output>입력된 데이터 타입 <class 'tuple'>
15 120<jupyter_text>- - -- - - 사전- 사전(dictionary)이란 key와 value 쌍으로 이루어진 hash table - - - 사전 관련 함수<jupyter_code>## 요소 확인하는 함수 - 값을 효율적으로 순회하거나 변경할 때 사용

dic = {1:1, 2:4, 3:9, 4:16, 5:25}

# .keys() => 키 리스트 받기
print(dic.keys())
print(list(dic.keys()))

# .values() => 값 리스트 받기
print(dic.values())
print(list(dic.values()))

# .items() => 키와 값 쌍으로 얻기
print(dic.items())
print(list(dic.items()))<jupyter_output>dict_keys([1, 2, 3, 4, 5])
[1, 2, 3, 4, 5]
dict_values([1, 4, 9, 16, 25])
[1, 4, 9, 16, 25]
dict_items([(1, 1), (2, 4), (3, 9), (4, 16), (5, 25)])
[(1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]<jupyter_text>- - -- - - 반복문과 comprehension - - - 대표적인 이터레이터 객체 생성 함수 : itertools 모듈 함수- itertools 모듈은 다양한 종류의 이터레이터 객체를 생성하는 함수로 구성됨<jupyter_code>import itertools

## itertools.product(*L)
# 순회가능한 여러 개의 객체를 순서대로 순회하는 이터레이터를 생성 (**다중 for문과 같다**)
count = 0
for a, b, c in itertools.product(range(2), range(2), range(2)):
	print(a, b, c)



## itertools.combination(p,r)
# 이터레이터 객체 p 에서 크기 r의 가능한 모든 *조합*을 갖는 이터레이터를 생성

L = ['a', 'b', 'c', 'd']
for comb in itertools.combinations(L, 2):
	print(comb)

# L에서 가능한 모든 조합 뽑기

for r in range(1, len(L) + 1):
	for comb in itertools.combinations(L, r):
		print(comb)

## itertools.permutations(p,r)
# 이터레이터 객체 p 에서 크기 r의 가능한 모든 *순열*을 갖는 이터레이터를 생성

for per in itertools.permutations(L, 2):
	print(per)<jupyter_output>('a', 'b')
('a', 'c')
('a', 'd')
('b', 'a')
('b', 'c')
('b', 'd')
('c', 'a')
('c', 'b')
('c', 'd')
('d', 'a')
('d', 'b')
('d', 'c')<jupyter_text>- - - Comprehension___list comprehension___- for문을 사용하여 한줄로 리스트 작성- 문법 : [output **for** element **in** iterator (**if** condition)]___dictionary comprehension___- for문을 사용하여 한줄로 사전 작성- 문법 : {~key~ : ~val~  **for** key, val **in** iterator (**if** condition)}<jupyter_code># 예시1 (dictionary comprehension)

dic1 = {x:y**2 for x,y in zip(range(10), range(10)) if x%2 == 0}
print(dic1)

# 풀어쓰면 아래와 같다
dic2 = dict()
for x, y in zip(range(10), range(10)):
	if x%2 == 0:
		dic2[x] = y ** 2
print(dic2)

# 예시2 (dictionary comprehension)
dic_ex1 = {1 : 'NaN', 2:2, 3:4, 4:'NaN'}
dic_ex2 = {x:y for x,y in dic_ex1.items() if y != 'NaN'}

print(dic_ex1)
print(dic_ex2)<jupyter_output>{1: 'NaN', 2: 2, 3: 4, 4: 'NaN'}
{2: 2, 3: 4}<jupyter_text>- - -- - - Numpy의 데이터 구조- Numpy의 자료형은 __ndarray__ ; 배열연산에 특화- 리스트와 ndarray는 유연성과 효율성을 기준으로 비교할 수 있다. - - - 리스트와 ndarray의 비교_리스트_- 유연성이 높고 효율성이 떨어짐- 서로 다른 데이터 타입의 요소를 담을 수 있으나, 각 요소 정보를 따로 저장하므로 반복문 사용이 필수적_ndarray_- 유연성이 낮고 효율성이높음- 서로 다른 데이터 타입의 요소를 담을 수 없으나, 모든 요소 정보를 한번에 저장하므로 C로 구현된 내부 반복문을 사용하여 속도가 매우 빠르다 - - - 사용방법<jupyter_code># np.array([...]) => ndarray의 작성
import numpy as np
a = np.array([1,3,2,5,3])
b = np.array([3.14, 4, 2, 3])
c = np.array([1,2,3,4], dtype = float)
print(a)
print(b) # 모든 자료형이 같아야 하므로, 모두 float으로 설정됨
print(c)
a
# array([..])<jupyter_output><empty_output><jupyter_text>- - - 다양한 함수<jupyter_code># np.zeros(shape) => shape(튜플) 모양을 갖는 영벡터/영행렬 생성

np.zeros((3,2))

# np.arange([start,] stop [, step]) => start부터 stop까지 step만큼 건너뛴 ndarray반환

np.arange(1, 5, 0.2)

# np.linspace(start, stop, num) => start부터 stop까지 num개수의 요소를 가지는 등간격의 1차원 배열 반환

np.linspace(0,1,9)<jupyter_output><empty_output><jupyter_text>- - - 인덱싱과 슬라이싱- 기본적인 인덱싱과 슬라이싱은 리스트와 완전 동일- 2차원 배열의 경우, X[i, j]는 i행j열의 요소를 나타냄 (리스트의 경우 X[i][j])- Bool리스트나, 여러개의 인덱스를 리스트 형태로 입력받을 수도 있다.<jupyter_code># 기본적인 인덱싱과 슬라이싱
x1 = np.random.random(size = (10, 5))

print("x1[0,1]:\n", x1[0,1])
print("x1[1:4, 2]:\n", x1[1:4, 2])
print("x1[0, 2:4]:\n", x1[0, 2:4])<jupyter_output>x1[0,1]:
 0.991458380474886
x1[1:4, 2]:
 [0.28552211 0.72780905 0.64592508]
x1[0, 2:4]:
 [0.1724539  0.87906146]<jupyter_text>- - - 유니버셜 함수- 유니버셜 함수는 ndarray의 개별요소에 반복된 연산을 빠르게 수행하는 것을 주 목적으로 하는 함수- 유니버셜 함수는 단순 반복문에 비해 매우 빠름<jupyter_code>x = np.array([1,2,3,4])
y = np.array([4,3,2,1])

print("x + y = ", x + y)
print("x - y = ", x - y)
print("x * y = ", x * y)
print("x / y = ", x / y)
print("log x = ", np.log(x))


# loop와 유니버셜 함수의 속도 비교
arr_1 = np.random.randint(1,10, size = 10 ** 8)
arr_2 = np.random.randint(1,10, size = 10 ** 8)

import time
t1 = time.time()
output = []
for val1, val2 in zip(arr_1, arr_2):
	output.append(val1 + val2) # 반복문과 리스트를 사용해서 합계 구현
t2 = time.time()
print("반복문을 사용한 경우 : ", round(t2 - t1, 4))

t1 = time.time()
output = arr_1 + arr_2 # 유니버셜 함수를 사용해서 구현
t2 = time.time()
print("유니버셜 함수를 사용한 경우", round(t2 - t1, 4), "   --> 압도적으로 빠르다")<jupyter_output>반복문을 사용한 경우 :  65.5616
유니버셜 함수를 사용한 경우 9.3789    --> 압도적으로 빠르다<jupyter_text>- - - 브로드캐스팅- 다른 크기의 배열에 유니버셜 함수를 적용하는 규칙 집합으로, 큰 차원의 배열에 맞게 작은 배열이 확장됨<jupyter_code>print(np.arange(3) + 5)
print()
print(np.ones((3,3)) + np.arange(3))
print()
print(np.arange(3).reshape(3,1) + np.arange(3))

# 브로드캐스팅 다른 예시 z ~ normalization

X = np.random.random((10, 3))
Xmean = X.mean(axis = 0) # 열별 평균 -> shape : (1,3)
Xstd = X.std(axis = 0) # 열별 표준편차 -> shape : (1,3)
Z = (X -Xmean) / Xstd  ## 브로드캐스팅을 통해 shape이 맞지 않더라도 복제되어 연산된다.

print("X:", X)
print("\nXmean:\n:", Xmean)
print("\nXstd:\n", Xstd)
print("\nZ:\n", Z)<jupyter_output>X: [[0.34526374 0.0068874  0.0648696 ]
 [0.02405672 0.33285715 0.77607038]
 [0.53832713 0.03900782 0.76152028]
 [0.53662339 0.87083756 0.05370867]
 [0.32347594 0.35124106 0.78431537]
 [0.9124582  0.76879527 0.57759713]
 [0.36505003 0.57848753 0.78177599]
 [0.14326022 0.06703938 0.40142469]
 [0.3084953  0.95590363 0.97143739]
 [0.45909972 0.94533755 0.7000227 ]]

Xmean:
: [0.39561104 0.49163943 0.58727422]

Xstd:
 [0.23008893 0.36257427 0.2991969 ]

Z:
 [[-0.21881668 -1.33697305 -1.74602282]
 [-1.61482919 -0.43793037  0.63100974]
 [ 0.62026493 -1.24838316  0.58237922]
 [ 0.6128602   1.0458495  -1.78332578]
 [-0.31350963 -0.38722653  0.6585668 ]
 [ 2.24629301  0.76441119 -0.03234354]
 [-0.13282261  0.23953189  0.65007949]
 [-1.09675342 -1.17107056 -0.62116127]
 [-0.37861768  1.28046648  1.28398109]
 [ 0.27593107  1.25132462  0.37683707]]<jupyter_text>- - - 비교 연산자- 비교 연산자의 결과는 항상 Bool 타입의 배열- 따라서 비교연산자의 결과를 바탕으로 조건에 맞는 요소 탐색에 활용가능<jupyter_code>L = np.array([1,2,3,4,5])
cond = L>=3
print(sum(cond)) # 조건을 만족하는 요소의 개수
print(L[cond]) # 조건을 만족하는 요소만 반환<jupyter_output>3
[3 4 5]<jupyter_text>- - -- - - Pandas의 데이터 구조- Series 와 DataFrame 으로 구성 - - - Series- **1차원 배열 자료형**으로 인덱스와 값의 쌍으로 구성- Series는 ndarray에 인덱스가 부여된 형태이므로 Series에서 유니버셜 함수와 브로드캐스팅 등이 적용된다.<jupyter_code>## Series의 작성

import pandas as pd

# 1. 사전을 이용한 작성법
print(pd.Series({'a':1, 'b':2, 'c':3, 'd':4}))

print()

# 2. 리스트를 이용한 작성법
print(pd.Series([1,2,3,4], index = ['a','b','c','d']))


s = pd.Series({'a':1, 'b':2, 'c':3, 'd':4})

print(s.values)
print(type(s.values))  # 인덱스를 제외하면 nparray이다<jupyter_output>[1 2 3 4]
<class 'numpy.ndarray'><jupyter_text>- - - DataFrame- **2차원 배열 자료형**으로 값, 행 인덱스(**보통 그냥 index라고 부름**), 열 인덱스(**보통 column으로 부름**) 로 구성- DataFrame은 ndarray에 행과 열 인덱스가 부여된 형태의 데이터- DataFrame은 **하나 이상의 Series의 집합**이라고도 볼 수 있다<jupyter_code>## DataFrame 의 작성법

# 1. 사전을 이용한 정의
df = pd.DataFrame({'Col1':[1,2,3,4], 'Col2':[5,6,7,8]}, index = ['a', 'b', 'c', 'd'])
print(df)

# 2. 데이터, 컬럼, 인덱스 따로 정의

## 이외에도 몇가지 방법이 더 있지만 생략
df.values
type(df.values) # 역시 값은 ndarray
type(df['Col1'])<jupyter_output><empty_output><jupyter_text>- - - Pandas의 인덱싱과 슬라이싱|암묵적 인덱스|명시적 인덱스|Data||--|--|--||0|a|1||1|b|2||2|c|3||3|d|4|- Pandas 객체는 암묵적 인덱스(위치인덱스)와 명시적 인덱스라는 두 종류의 인덱스가 있음- **명시**적 인덱스를 참조하는 **loc 인덱서**와 **암묵**적 인덱스를 참조하는 **iloc 인덱서**가 있다<jupyter_code>print(s, '\n')

print("s.loc['a'] = ", s.loc['a'])
print("s.iloc[2] = ", s.iloc[2])

## 주의사항
# loc를 이용한 슬라이싱에서는 맨 뒤 값을 포함한다
print(s.loc['a':'c'])
# iloc를 이용한 슬라이싱 에서는 맨 뒤 값을 포함하지 않는다.
print(s.iloc[0:2])


## dataframe 의 인덱싱 및 슬라이싱
df

# series 반환
df['Col1']

# dataframe 반환 (리스트형태의 인자)
df[['Col1']]

print(df.loc['a':'c', 'Col1'])
print()

print(df.iloc[0:3, 0])<jupyter_output>a    1
b    2
c    3
Name: Col1, dtype: int64

a    1
b    2
c    3
Name: Col1, dtype: int64
{'fraction_non_alphanumeric': 0.1921788916495625, 'fraction_numerical': 0.10889056929890893, 'mean_word_length': 3.7355498721227622, 'pattern_counts': {'":': 0, '<': 50, '<?xml version=': 0, '>': 69, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '14', 'dir': 'jupyter-structured-clean-dedup', 'id': '530075', 'license': 'Apache-2.0', 'n_tokens_mistral': 6501, 'n_tokens_neox': 7090, 'n_words': 1228, 'path': '_notebooks/2021-11-11-ML-preprocessing1-2.ipynb', 'repo_name': 'Jaysung00/jays_blog', 'size': '9259'}