# =============================================================================
#
# # 파이썬 자료 구조
#
# 1. 리스트
# - 기본 자료 구조(내장된)
# - R의 벡터와 비슷
# - 1차원
# - 서로 다른 데이터 타입 허용
# 2. 딕셔너리
# - 기본 자료 구조
# - R의 리스트와 비슷
# - key와 value 형태로 구성
# 3. 배열
# - numpy 모듈 지원 자료 구조
# - R의 배열과 동일
# - 다차원
# - 하나의 데이터 타입만 허용
# 4. 시리즈(내장되어 있지 않다는 것 말고 성격적으로 더 비슷하네)
# - pandas 모듈 지원 자료 구조
# - 1차원
# - R에서의 벡터와 동일
# - 서로 같은 데이터 타입만 허용
# - 데이터 프레임의 컬럼을 구성하는 기본 자료 구조
# 5. 데이터프레임
# - pandas 모듈 지원 자료 구조
# - R에서의 데이터프레임과 동일
# - 행과 열의 구조(key(컬럼)-value)
# - 2차원
# =============================================================================
# 리스트 : 파이썬 기본 자료구조, 1차원, 서로 다른 데이터 타입허용
# 1. 생성
l1 = [1,2,3]
type(l1) # class는 벡터면 벡터가 아닌 해당 안에 원소들의 타입을 반환했지만 다름
l2 = [1,2,3,'4']
l2
l3 = [1,2,3,[4,5]] ; l3
#R에서는 벡터에 벡터를 중첩시켜도 그냥 나열된 상태로 나왔으나, 이것은 중첩이 됨(리스트는 서로 다른 데이터 타입을 허용해서 그런듯.)
#리스트안에 리스트를 넣을 수 있으나 1차원임.
#중첩된 것의 색인은 2차원 비스무리하게 되긴 함.
l3[3][0]
type (l2)
# 리스트는 여러개를 묶거나 묶은채로 전달할 때 빈번히 사용됨
# 2. 색인
l1[0]
l1[0,2] # 2차원으로 인식된다는 듯.
l1[[0,2]] # 이것도 안된다. 동시에 여러개 색인 불가(리스트를 사용한 색인 불가)
l1[1:2] # 두번째 원소에서 두번째 까지 추출 # 슬라이스 색인하면 차원축소 방지함.
# 슬라이스 색인 : x1~x2까지 같은거
l1[1] # 정수 하나 추출시 차원축소
l1[0:1] #?
l1[0:2] # 첫번째 원소에서 두번째 원소 추출 #0,1추출 2개 추출
# n:m => n~ (m-1)까지 추출
l1[-1] # 뒤에서 첫번째 원소 추출
# [참고 : 시리즈에서의 리스트 색인]
from pandas import Series
s1 = Series(11)
s1[[0,2]] #리스트를 사용한 색인 가능
# 3. 연산
l1 = [1,2,3]
l2 = [10,20,30]
l1 + 1 #파이썬의 주요한 특징, 벡터와 같은 반복적인 연산들 안됨
#(사상 자체가 반복문을 확실히 프로그래밍하지 않으면 안되도록 함)
l1 + l2 #각각 연산이 되는게 아니고 합집합이 나옴
l1 * 3 #l1 + l1 + l1 이 되어서 우리가 아는 산술연산이 되는게 아님
#원소별로 값을 전달하고 싶다면 적용함수를 이용해야한다.
# math 모듈 내 함수
import math
#파이썬 기본창에서는 math. 만써도 여러 함수들이 보이는데 스파이더에선 안된다고 하심
#내장된 함수 목록 #중요!!!
dir(math)
math.sqrt(9) #제곱근
2**3 #거듭제곱 연산자
math.pow(2,3) #거듭제곱 함수
# 문자열 관련 함수 (리스트에는 적용 안됨)
# 문자열 관련 표현식
# 1. 문자열 색인
v1 = 'abcde'
v1[1] # b 출력
v1[0:3] # abc 출력
#cf. In R : 문자열 자체가 하나의 원소라 str_sub이나 split없이 하나씩 알파벳을 추출하지 못했음
# 2. 다중 라인 문자열 생성
# v2 = 'abcde
# 12345'
# vsql = 'select *
# from emp'
#줄바꿔서 입력 안됨
vsql ='''select *
from emp'''
#'''를 이용해서 입력 가능 #현재 왜안되누? 두줄 모두 잡고 실행해야함
vsql
vsql ="""select *
from emp"""
# 3. 문자열 메소드 (string)
s1 = 'abcde'
s2 = 'ABCde'
l1 = ['abc','ABC']
#1) 대소치환
s1.upper()
s2.lower()
s1.title() #camel표기법
#2) startswith : 문자열의 시작 여부 확인
s1.startswith(data, #시작값 확인문자
start, #검사 시작 위치(생략가능)
end) #검사 끝 위치(생략가능)
s1.startswith('A') #A로 시작합니까?
#문자열내에 문자 색인이 가능해서 굳이 이 메서드가 필요한가 싶음
s1[2] == 'c' #3번째 글자가 c 입니까?
s1.startswith('c',2) #3번째 글자가 c 입니까?
#3) endswith : 문자열의 끝 여부 확인
s1.endswith('e')
l1.startswith('a') # l1과 startswith는 어울리지 않기에 attribute에러 메세지 출력함
#list의 원소는 문자열이니까 하나씩 뽑아서 전달하면 가능, 반복문이나 적용함수로 해결 가능할 듯
# 4) strip : 공백제거
' abcd '.rstrip() # 오른쪽 공백 제거
' abcd '.lstrip() # 왼쪽 공백 제거
' abcd '.strip() # 양쪽 공백 제거
'abcde'.lstrip('a') # 문자열을 전달하면 문자열 제거가능하나 a를 제거하다 a가 아닌 녀석을 만나면 멈춤(연속된 a 제거 가능) . 중간에 있는 a 제거 불가
# 5) replace : 치환
'abcde'.replace('a','A') #치환
'abcde'.replace('c','') #제거
# 6) split : 분리
'a;b;c'.split(';') #출력 결과 리스트
# 7) find : 특정 문자의 위치값 리턴 # str_locate
'abcde'.find('a') #0 #'a'의 위치 리턴
'abcde'.find('A') #없으면 -1 리턴 #이걸 활용하면 특정값의 포함여부를 확인할수도 있음
'abcde fg 1234'.find('1234')
# 8) count : 포함 횟수 리턴
'abcabcaa'.count('a') #4번 쓰임
# 9) 형(type) 확인
'abd'.isalpha() #문자 구성 여부
'abd'.isnumeric() #숫자 구성 여부
'abd'.isalnum() #문자/숫자 구성여부
# 10) format : 포맷 변경
'{0:.2f}'.format(10)
#연습문제
ename = 'smith'
tel = '02)345-7839'
jumin = '901223-2223928'
vid = 'abc1234!'
# 1)ename의 두번째 글자가 m으로 시작하는지 여부
ename[1] == 'm'
ename.startswith('m',1)
# 2) tel 에서 국번 (345) 출력
tel.split(')')[1].split('-')[0]
#------------------another
vno1 = tel.find(')') #정규식표현식이 불가능한 메서드 , 그래서 escape 문자도 필요 없음
vno2 = tel.find('-')
tel[3:6]
tel[vno1+1:vno2]
#마찬가지로 split의 경우도 정규식표현식이 불가능
# 참고로 pandas에서 제공하는 split메서드는 정규식 지원됨 # 데이터프레임타입.split
# 정규식 표현은 R에서 배운것과 동일한 규칙
# 3) jumin에서 여자 여부 출력
jumin.find('-2') != -1
#------------another
jumin[7] == 2 #false # 형일치 정확하게 해야함
jumin[7] == '2' #true
# 4) vid에서 !가 포함되어 있는닌지 여부 출력
vid.find('!') != -1
#4. 문자열 결합
'a' + 'b' # '+'기호가 어떤타입에 붙느냐에 따라 다르게 적용 됨
# =============================================================================
# #cf. 연결 연산자 in ORACLE , in R
# #in ORACLE
# # 'a' || 'b'
#
# #in R
# # stringr::str_c('a','b')
# # paste(c('a','b')) # str_c(c('a','b'), collapse = '') 둘이 같은?
# # paste('a','b', sep='')
#
# =============================================================================
#5. 패턴확인(포함여부)
'abcde'.find('c') #로 -1이면 포함x, 그 외값이면 포함
'c' in 'abcde' #문자열 in #일치가 아니고 패턴의 포함여부임
ename = ['smith','allen','ward','scott']
(ename == 'smith') or (ename == 'allen')
#조건 확인의 경우에도 각자에 전달 안된다
#?
ename in ['smith', 'allen']
#?
# 6. 문자열 길이 확인
len('abcde')
# 예제 - 지폐환산 (돈입력받고 5만원~1000원 단위로 돈바꾸고 나머지 잔돈까지)
# 다 작성후 한번에 여러줄 잡고 f9
# 또는 파이썬 IDLE - File - new file - 여기에 코드 써놓고 F5키로 한번에 실행
# F5 누르면 저장하라고 하는데 디폴트 디렉토리 아닌 곳에 저장해도 상관은 없음
total = int(input('지폐로 교환할 돈은 얼마?'))
c_50000 = total/50000 #몫은 // 이 정확하긴 함 # / 하고 나중에 %d로 형변환 해서 값 잘려서 정상적으로 출력되는것임
rest1 = total%50000
c_10000 = rest1/10000 # %/% in R
rest1 %= 10000 # %% in R
c_5000 = rest1/5000
rest1 %= 5000
c_1000 = rest1/1000
rest1 %= 1000
print("50000원 짜리 ==> %d장" %c_50000) #print("50000원 짜리 ==> c_50000" ) #c_50000이 문자로 읽혀서, 뒤로 빼놓고 전달하는 방식을 취하는 것임
print("10000원 짜리 ==> %d장" %c_10000)
print("5000원 짜리 ==> %d장" %c_5000)
print("1000원 짜리 ==> %d장" %c_1000)
print("잔돈 ==> %d원" %rest1)
#개선 사항 : 출력 가지런하게
total = int(input('지폐로 교환할 돈은 얼마?'))
c_50000 = total/50000
rest1 = total%50000
c_10000 = rest1/10000
rest1 %= 10000
c_5000 = rest1/5000
rest1 %= 5000
c_1000 = rest1/1000
rest1 %= 1000
print("50000원 짜리 ==> %2d장" %c_50000)
print("10000원 짜리 ==> %2d장" %c_10000)
print("5000원 짜리 ==> %2d장" %c_5000)
print("1000원 짜리 ==> %2d장" %c_1000)
print("\n잔돈 ==> %d원" %rest1)
#\n 아니면 print자체가 개행의 의미가 있으므로 print()를 1000원과 잔돈 사이에 넣거나
# =============================================================================
# #[참고 : 함수와 메소드의 차이]
# func1(x,y,z) = x + y + z
#
# func1(data,x,y) #함수
#
# data.func1(x,y) #메소드
#
# #파이썬이 메소드를 선호하는 이유
#
# from pandas import Series
# s1 = Series([1,2,3,4])
#
# s1.order #'Series' object has no attribute 'order' // order를 적용할 수있는 속성이 없음
# s1.map? #시리즈타입에 map #메소드 사용 설명
#
# # 메소드는 데이터형을 앞으로 뺀 형태라서 , 해당 데이터에 메소드의 적용의 적합여부를 메소드 실행 전에 확인 가능
# # 함수는 파싱을 하면서 데이터가 적절하지 않음을 파악
#
# =============================================================================
# 논리연산자
v1 = 100
(v1 > 50) and (v1 < 150)
(v1 > 50) & (v1 < 150)
(v1 > 50) or (v1 < 150)
(v1 > 50) | (v1 < 150)
#R과 비교하자면 문자로 표현이 가능해짐
not(v1 > 50) # !(v1 > 50) 은 안됨
#리스트 조건 전달
l1 = [1,2,3,4,5]
l1 > 3 #리스트와 정수의 대소비교 불가
l1 == 1 #같다. 같지 않다는 벡터연산 불가
# =============================================================================
# #사용자 정의함수 # 1. 중복된 코드 줄이기 2. 적용함수에 함수명을 인자로 전달하고자
#
# # 정식적인 사용자 정의함수
# #문법적인 묶음을 {} 가 아닌 : 을 사용함
# # def f1 : ~~~~
# #추후에 배울것임
#
# =============================================================================
# lambda 를 사용한 사용자 정의함수 생성(축약형)
#- 축약형 사용자 정의 함수 생성 문법
#- 간단한 return 만 가능
#- 복잡한 프로그래밍 처리 불가
# 함수명 = lambda input:output
#[예시1]
# y = x+1
f1 = lambda x : x + 1
f1(5)
#[예시2]
#인자 2개
f2 = lambda x,y : x + y
f2(2,10)
#[예시3]
#인자의 default 값
f3 = lambda x, y=0 : x + y
f3(2,10)
#주의
f4 = lambda x = 0, y : x + y #앞에 input value만 디폴트값 선언 불가, 디폴트값을 정한 x 뒤에 오는 모든 변수들은 디폴트값을 가져야함
#정확히는 모르지만 인자를 순서대로 전달하는것과 관련이있으려나 싶긴함
# =============================================================================
# 적용 함수 : map
# - 1차원 적용함수 : 데이터 셋의 함수의 반복 적용 가능
# - 결과 출력시 list함수 사용 필요
# - 함수의 추가인자 전달 가능
map(func, *iterables) # *변수이름 <- 가변형 변수이다
l1 + 1 # 벡터연산 불가
map(f1, l1) # <map at 0x1a5fbb5ffc8> 적용해서 메모리에 값을 올려놓고 출력은 x
list(map(f1, l1)) #이렇게 하면 제대로 출력 됨
# =============================================================================
# 예제) 다음 두 리스트의 각 원소의 합을 출력
l1 = [1,2,3,4,5]
l2 = [10,20,30,40,50]
l1 + l2 #리스트 연산 불가, 확장
#cf.Series 는 가능
f2 = lambda x,y : x + y
list(map(f2,l1,l2))
# 예제) 다음 리스트의 각 원소를 대문자로 변경
l3 = ['a','b','ab']
l3.upper() #리스트에 적용 불가
f3 = lambda x : x.upper()
list(map(f3,l3))
#[연습문제]
#다음의 리스트를 생성
L1 = [1,2,3,4]
L2 = [10,20,30,40]
L3 = ['서울','부산','대전','전주']
L4 = ['abc@naver.com', 'a123@hanmail.net']
# 1. L2의 L1승 출력, 10^1, 20^2, ...
f1 = lambda x,y : x**y
list(map(f1, L2, L1))
# 2. L4의 값에 '시'를 붙여 출력
f2 = lambda x : x+'시'
list(map(f2,L3))
# 3. L4에서 이메일 아이디만 출력
f3 = lambda x : x.split('@')[0]
list(map(f3, L4))
#---------another
f3_1 = lambda x : x[0:x.find('@')]
list(map(f3_1,L4))
# 추가 문제 :
# split의 구분기호를 입력받고, 위치값을 전달 받아 분리된 것중 선택하여 추출
f5 = lambda x,y,z : x.split(y)[z]
l1 = ['a;b;c', 'A;B;C']
#적용전에 스칼라에 대한 test부터
f5('a;b;c', ';', 1)
f5(l1,';',1) #불가
list(map(f5,l1,';',1)) #'int' object is not iterable
#test 예시1
f6 = lambda x,y=';',z='0' : x.split(y)[z] #디폴트값을 넣어주면 달라지려나 해서 해보심
list(map(f6,l1,';',1)) #안됨
# =============================================================================
# [참고 - 함수의 인자전달 방식 in R]
#
# sapply(vect , 함수 , 나머지인자1, 나머지인자2)
# 함수 앞에 있는 vect 만 하나씩 찢어서 전달함.
# =============================================================================
#
# map (함수, 인자1, 인자2, 인자3)
#함수 뒤에 있는 인자들 모두 세트로 묶어서 전부 하나씩 전달함. 근데 test 예시1 의 ;가 1개라서 찢어서 전달이 안되서 에러가 발생 하는 것.
list(map(f6,l1,[';',';'],[0,0])) #이렇게 갯수 맞춰주면 원하던 결과 얻을 수 있음
list(map(f6,l1,[';',';'],[0,1])) #갯수만 맞으면 이렇게 다르게 전달 가능한 점의 장점
#[예제]
# 다음의 리스트이 각원소가 a로 시작하는지 여부 확인
l1 = ['abc','ABC','bcd']
l1.startswith('a') #불가
list(map(lambda x:x.startswith('a'),l1))
list[[True, False, False]] #R처럼 색인이 불가능, list색인 불가능 하기 때문에 조건 색인도 불가능
Series(l1)[[True, False, False]] #시리즈는 리스트색인 가능(조건색인도 가능)
# 리스트의 특징 추가 정리
# 1. 생성
l1 = [1,2,3,4]
l2 = [1,2,3,4,5,6]
# 2. 색인
l1[0] # 차원 축소되어서 첫번째 원소
l1[0:0] # 빈리스트만 나옴
l1[0:1] # 첫번째 원소 차원 축소 없이 출력
l1[[0,2]] #리스트로 1번째 3번째 출력 불가
l1[-1]
l2[::2] #시작값: 끝값+1: 증가값
# 3. 연산
l1 + 1 #불가
list(map(lambda x:x+1, l1)) #이렇게 해야함
# 4. 확장
l1 + l2 #두 리스트의 합집합
l1.append(5) # 5 라는 원소 추가, 출력없이 바로 수정됨
l1 + [7] #추가해서 출력해서 보여줌 , 원본이 수정되는건 아님
l2.extend([7]) #리스트값으로 추가하여 원본객체를 즉시수정 #출력 x
# 위에 2개의 원리는 비슷
# 5. 수정
l1[0] = 10 ;l1
l1[1] = [20,30] ; l1 #2번째 원소를 해당 리스트로 대체 #출력 [10, [20, 30], 3, 4, 5]
l1[2:4] = [300,400] ; l1 #각각 수정
l2[7] = 8 #out of range 에러 발생, 정의되지 않은 position에 값 할당 불가
#in R
#빈 벡터의 i번째 값이 수정이 된다고 하는데 , 내 기억에는 안됨
# v1 <- c()
# for ... {
# v[i] <- ...
# }
# 6. 삭제
del(l1[1]) #값 삭제 후 원본 수정
del(l1) #객체 자체 삭제 가능
#들어가는 값 자체를 지워줌
l2 = [] #객체는 유지, 원소만 전체 삭제
# =============================================================================
# 함수,메소드의 설명 보기
# 함수의 경우
round? #함수 설명 나옴 # 왜 지랄인지 모르겠는데, 그냥 줄실행은 안되고 글자 블록잡아주고 f9눌러야 되네
# 메소드의 경우
append? #메소드라서 설명 안나옴
l1.append? #메소드는 적용할 데이터형식을 붙여서 질문을 해야 설명 찾아준다
# =============================================================================
round?
#왜인지는 모르겠는데 물음표 뒤에 스페이스로 빈공간만 들어가도 출력 안됨
# =============================================================================
# 실습문제
# =============================================================================
# 1. 문자열, 찾을 문자열, 바꿀 문자열을 입력 받아 변경한 결과를 아래와 같이 출력
# 전 :
# 후 :
x = input("문자열 교체 \n 문자열 :")
y = input('찾을 문자열 :')
z = input('바꿀 문자열 :')
after_str = x.replace(y,z)
print('전 : %s' % x)
print('후 : %s' % after_str)
# 2. 이메일 주소를 입력받고 다음과 같이 출력
# 아이디 : a1234
# 메일엔진 : naver
e_mail = input('이메일 입력해주세요:')
print('아이디 : %s' %e_mail.split('@')[0])
print('메일엔진 : %s' %e_mail.split('@')[1].split('.')[0])
print('%s'% 'http://kic.com/'+e_mail.split('@')[0])
# 3. 2번을 활용하여 다음과 같은 홈페이지 주소 출력
# http://kic.com/a1234
# 4. num1='12,000' 의 값을 생성 후, 33으로 나눈 값을 소숫점 둘째짜리까지 표현
num1 = '12,000'
num1 = int(num1.replace(',', ''))
round(num1/33,2)
print('%.2f' % num1/33) #이건 왜 안될까욤
# 5. 다음의 리스트 생성 후 연산
ename = ['smith','allen','king']
jumin = ['8812111223928','8905042323343','90050612343432']
tel=['02)345-4958','031)334-0948','055)394-9050','063)473-3853']
vid=['2007(1)','2007(2)','2007(3)','2007(4)']
# 1) ename에서 i를 포함하는지 여부 확인
f_find_judge = lambda x : x.find('i') != -1 # y라는 문자로 'i' 말고 다른 문자도 하고 싶지만 map에 적용되면 문제가 될수 있음
list(map(f_find_judge,ename))
# 2) jumin에서 성별 숫자 출력
f_jumin_gender = lambda x:x[6]
list(map(f_jumin_gender,jumin))
# 3) ename에서 smith 또는 allen 인지 여부 출력 [True,True,False]
list(map(lambda x:(x=='smith')or (x=='allen'),ename))
# 4) tel에서 다음과 같이 국번 XXX 치환 (02)345-4958 => 02)XXX-4958)
f_xxx = lambda x: x.replace(x[x.find(')')+1:x.find('-')],'XXX')
list(map(f_xxx, tel))
'abcde'.find('c') # 2
# 5) vid 에서 각각 년도와 분기를 따로 저장
f_year = lambda x : x.split('(')[0]
year = list(map(f_year, vid))
f_quar = lambda x : x[x.find('(')+1:x.find(')')]
quar = list(map(f_quar,vid))
year
quar
f_int = lambda x: int(x)
year = list(map(f_int, year))
quar = list(map(f_int, quar))