# matplotlib 말고 그래프를 그릴 때 사용하는 패키지는?
[답변]
seaborn
# 데이터의 summary 를 돌려주는 함수는?
[답변]
descibe()
# 빈도수 그래프를 보기 위한 함수는?
[답변]
countplot
# value_counts는 한개의 칼럼에만 적용된다 (o x)
[답변]
x
[출제자 답변]
o
데이터 프레임과 시리즈 형태에 모두 적용할 수 있는 count()와 다르게
value_counts()는 데이터 프레임에 적용할 수 없다.
보통 시리즈(한줄)에 대해서만 하며, 값을 세고 싶은 특정 컬럼을 설정하여 사용해야한다.
# 아래 예시에서 immutable 과 mutable 타입으로 각각 분류하시오
(dic, int, float, list, str, tuple)
[답변]
immutable : int, float, str, tuple
mutable : list, dict
[추가 설명]
수정이 불가능한 객체를 immutable 객체
수정이 가능한 객체를 mutable 객체라고 부른다.
# pandas를 이용하여 아래의 데이터 프레임을 만들어 보세요
# v1 v2
# 0 1 5
# 1 2 3
# 2 1 2
[답변]
import pandas as pd
pd.DataFrame({'v1': [1, 2, 1], 'v2': [5, 3, 2]})
pd.DataFrame({'v1':(1,2,1),'v2':(5,3,2)})
# 위에서 만들어진 데이터 프레임에 칼럼명을 대문자로 바꿔주세요
[답변]
# 만들어진 값을 일단 어딘가에 저장한 후
a = pd.DataFrame({'v1':(1,2,1),'v2':(5,3,2)})
# rename 사용
a.rename({'v1' : 'V1', 'v2' : 'V2'},axis=1)
# 종강일은 2023년 2월 24일이다.
# datatime lib를 사용하여 종강일까지 남은 일수를 구해보세요
[답변]
import datetime
end = datetime.datetime(2023, 2, 24)
today = datetime.datetime.now()
end - today
# datetime.timedelta(days=155, seconds=52888, microseconds=349137)
# 155일 남았다
# 아래와 같은 데이터 프레임을 만들어보세요
# a b
# 0 1 4
# 1 2 5
# 2 3 6
[답변]
a = pd.DataFrame({'a' : [1, 2, 3], 'b' : [4, 5, 6]})
pd.DataFrame(np.array([[1, 4], [2, 5], [3, 6]]), columns=['a', 'b'])
pd.DataFrame([[1, 4], [2, 5], [3, 6]], columns=['a', 'b'])
# 위 데이터 프레임에서 컬럼명을 대문자로 바꿔주세요
[답변]
df = pd.DataFrame(np.array([[1, 4], [2, 5], [3, 6]]), columns=['a', 'b'])
df.rename({'a':'A', 'b':'B'}, axis=1)
# 위 데이터 프레임에서 두 열의 합을 구해 새로운 열을 만들어주세요
[답변]
df['hap'] = df['A'] + df['B']
# Interable 객체에 대하여 틀린 것을 고르시오
# 1 )순회가능한 반복되는 객체이다
# 2) int형 객체를 포함한다
# 3) for 반복문에 넣어 사용 가능하다
# 4) tuple형 객체를 포함한다
[답변]
2
# 동적 타이핑의 한 종류로 객체가 어떠한 타입에 걸맞는 변수와 메소드를 지닌다면
# 이 객체를 해당 타입에 속하는 것으로 간주하는 것을 무엇이라 하는가
[답변]
덕 타이핑
# -별로 색을 넣으려 할때 color 안에 무엇이 들어가야 하는가
# sns.countplot(data = df, x = , color = )
[답변]
hue
# 데이터 프레임의 구조를 알아보기 위해 사용하는 함수는?
[답변]
info()
# excel_exam.xlsx 파일을 df 로 읽어라
[답변]
df = pd.read_excel("excel_exam.xlsx")
# 읽어온 파일에서 수학, 영어, 과학의 평균을 구한후, 평균 칼럼을 만들어보세요
[답변]
df['평균'] = (df['math'] + df['english'] + df['science']) / 3
# 평균 칼럼의 그래프를 그려보세요
[답변]
df = pd.read_excel("excel_exam.xlsx")
df['평균'] = (df['math'] + df['english'] + df['science']) / 3
df['평균'].plot(kind = 'hist')

# 합격 여부라는 열을 만들어 평균 칼럼의 값이
# 60이 넘는 학생에게는 합격, 그 외에는 불합격을 부여하시오
[답변]
df['합격여부'] = np.where(df['평균']>60, '합격', '불합격')
# 만들어진 합격여부 열을 countplot을 사용해 그래프로 그려주세요
[답변]
import seaborn as sns
sns.countplot(data= df, x='합격여부')

배열의 각 원소를 빠르게 처리하는 함수를 유니버셜 함수라 부른다. ufunc라고 불리기도 하는데, ndarray 안에 있는 데이터 원소별로 연산을 수행한다.
단항 유니버셜 함수는 간단한 변형을 전체 원소에 적용할 수 있다.
이항 유니버셜 함수는 2개의 인자를 취해 단일 배열을 반환한다.
# 단항 유니버셜 함수 예시
arr = np.arange(10)
# 간단한 변형을 전체 원소에 적용
np.sqrt(arr)
# 이항 유니버션 함수 예시
x = np.random.randn(8)
y = np.random.randn(8)
np.add(x, y)
| 함수 | 설명 |
|---|---|
| abs, fabs | 각 원소(정수, 부동소수점수, 복소수)의 절댓값을 구한다. 복소수가 아닌 경우에는 빠른 연산을 위해서 fabs를 사용한다. |
| sqrt | 각 원소의 제곱근을 계산한다. arr **0.5 와 동일 |
| square | 각 원소에서 제곱을 계산한다. arr **2와 동일 |
| exp | 각 원소에서 지수를 계산한다 |
| log, log10, log2, log1p | 각각 자연로그, 로그10, 로그2, 로그(1+x) |
| sign | 각 원소의 부호를 계산한다 |
| ceil | 각 원소의 소수자리를 올린다. 각 원소의 값보다 같거나 큰 정수 중 가장 작은 정수를 반환한다. |
| floor | 각 원소의 소수자리를 내린다. 각 원소의 값보다 작거나 같은 정수 중 가장 작은 수를 반환한다. |
| rint | 각 원소의 소수자리를 반올림한다. dtype은 유지된다. |
| modf | 각 원소의 몫과 나머지를 각각의 배열로 반환한다 |
| isnan | 각 원소가 숫자가 아닌지를 나타내는 불리언 배열을 반환 |
| isfinite, isinf | 각각 배열의 각 원소가 유한한지 무한한지 나타내는 불리언 배열을 반환한다. |
| cos, cosh, sin, sinh, tan, tanh | 일반 삼각함수와 쌍곡삼각함수 |
| arccos, arccosh, arcsin, arcsinh, arctan, arctanh | 역삼각함수 |
| logical_not | 각 원소의 논리 부정(not)값을 계산한다 ~arr과 동일 |
| add | 두 배열에서 같은 위치의 원소끼리 더한다 |
|---|---|
| subtract | 첫 번째 배열의 원소에서 두 번째 배열의 원소를 뺀다 |
| multiply | 배열의 원소끼리 곱한다 |
| divide, floor_divide | 첫 번째 배열의 원소를 두 번째 배열의 원소로 나눈다 floor_divide는 몫만 취한다. |
| power | 첫 번째 배열의 원소를 두 번째 배열의 원소만큼 제곱한다 |
| maximum, fmax | 각 배열의 두 원소 중 큰 값을 반환한다. fmax는 NaN을 무시한다 |
| minimum, fmin | 각 배열의 두 원소 중 작은 값을 반환한다. fmin은 NaN을 무시한다 |
| mod | 첫 번째 배열의 원소를 두 번째 배열의 원소로 나눈 나머지를 구한다. |
| copysign | 첫번째 배열의 원소와 기호를 두번째 배열의 원소 기호로 바꾼다 |
조건에 맞는 데이터 추출하기. 예시를 보자
exam = pd.read_excel("excel_exam.xlsx")
# pandas의 query()를 이용해 조건 하나 걸기
# 수학점수가 50 이상인 경우 출력
exam.query('math >= 50')
# 조건 두개 걸기
# 수학점수가 50이상 영어점수는 90 초과
exam.query('math >= 50 and english > 90')
그런데 처리를 하다보면 나는 class==1 의 조건을 걸고 싶은데 python keyword not valid identifier in numexpr query pandas 오류가 뜨는 것을 확인할 수 있다. 이는 class가 예약어이기 때문임으로 이름을 변경하여 주면 무리 없이 사용 가능하다.
# 1반이고 수학이 50점 이상
exam = exam.rename({'class':'nclass'}, axis=1)
exam.query('nclass == 1 and math >= 50')
| 기호 혹은 in[]을 이용하여 여러 조건을 나열할 수도 있다.
# ex) 1, 3, 5 반에 해당하는 값들을 추출하고 싶다
exam.query('nclass == 1 | nclass == 3 | nclass == 5')
exam.query('nclass in [1, 3, 5]')
함수를 조합해서 검색하는 것도 가능하다
exam.query('nclass == 1')['english']
문자 검색도 가능하다. 단 query()에 전체 조건을 감싸는 따옴표와 문자를 감싸는 따옴표를 서로 다른 모양 으로 입력해야 합니다.
# 예시로 사용할 데이터 프레임 생성
df = pd.DataFrame({'sex' : ['F', 'M', 'F', 'M'],
'country' : ['Korea', 'China', 'Japan', 'USA']})
# 검색
df.query('sex == "F" & country == "Korea"')
df.query("sex == 'F' and country == 'Korea'")
df.drop()을 이용하면 됩니다. 제거할 변수명을 columns 에 입력하면 입력한 변수만 제외하고 모든 변수를 추출한다.
exam.drop(columns='math')
# 여러 변수 제거시 `[]` 안에 제거할 변수명을 나열하면 된다.
exam.drop(columns=['id', 'nclass'])
df.sort_values()에 정렬 기준으로 삼을 변수를 입력하면 기준에 따라 오름차순으로 정렬된다.
# 수학 점수가 낮을 사람부터 높은 사람 순으로 출력
exam.sort_values('math')
내림차순으로 정렬하려면 ascending = False 로 기능을 꺼주면된다.
exam.sort_values('math', ascending = False)
정렬기준으로 삼을 변수를 여러 개 지정하려면 [] 안에 변수명을 나열하면 된다. 이때, 왼쪽에서 오른쪽에 쓰인 순으로 정렬한다.
# nclass를 기준으로 오름차순 정렬한 다음
# 정렬된 기준(각 반)에서 수학점수를 기준으로 오름차순 정렬
exam.sort_values(['nclass', 'math'])
# 변수별로 정렬 순서를 다르게 지정하려면
# `ascending`도 []를 사용해 묶어주면 된다
exam.sort_values(['nclass', 'math'], ascending=[True, False])
새 변수명 = 변수를 만드는 공식 을 입력하면 되는데, 이때 새로 만들 변수명에는 따옴표를 입력하지 않는다.
# 따옴표 하지 않는 total
exam.assign(total = exam['math']+exam['english']+exam['science'])
'집단별 평균' 과 같이 각 집단을 요약한 값을 구할 때는.groupby()와 .agg()를 사용한다.
# 수학 평균 구하기
# 행 이름 = (계산할 컬럼, '어떤 값을 얻고 싶은가')
# 수학 점수의 평균을 구하고 싶다
exam.agg(mean_1 = ('math', 'mean'))
# 각 집단별로 묶어서 각각에 대하여 최솟값
exam.groupby('nclass').min()
# id math english science
# nclass
# 1 1 30 86 50
# 2 5 25 78 25
# 3 9 20 65 15
# 4 13 46 56 12
# 5 17 65 68 58
# 그런데 위를 보면 nclass가 인덱스가 되어있다.
# goupby()는 안에 들어간 기본값을 인덱스로 사용하며
# 이게 싫다면 as_index=False 옵션을 달아주면 된다.
# nclass id math english science
# 0 1 1 30 86 50
# 1 2 5 25 78 25
# 2 3 9 20 65 15
# 3 4 13 46 56 12
# 4 5 17 65 68 58
# 만약 구해진 값을 모두 보지 않고 특정 열만 보고싶다면
exam.groupby('nclass').min()[['math', 'science']]
# 혹은 전체값은 필요없고 몇 열만 필요한 경우라면
exam[['nclass', 'math', 'science']].groupby('nclass').min()
집단 별 요약 통계량을 구해보자
df.groupby()에 변수를 지정하면 변수의 범주별로 데이터를 분리한다. 여기에 agg()를 적용하면 집단별 요약 통계량을 구할 수 있다.
# \ = 이어주는 기호. 이래 위는 한줄이다라는 표시
# nclass 별로 먼저 분리하고
# math 평균을 구했다.
exam.groupby('nclass') \
.agg(mean_math = ('math', 'mean'))
# 만약 여러 통계랑을 한번에 구하고 싶다면
exam.groupby('nclass') \
.agg(mean_math = ('math', 'mean'),
sum_math = ('math', 'sum'))
다음은 agg() 에 자주 사용하는 요약 통계량 함수이다
| 함수() | 통계량 |
|---|---|
| mean() | 평균 |
| std() | 표준편차 |
| sum() | 합계 |
| median() | 중앙값 |
| min() | 최소값 |
| max() | 최대값 |
| count() | 빈도(개수) |
groupby()에 여러 변수를 지정하면 집단을 나눈 다음 다시 하위 집단으로 또 나눌수 있다. 예를 들어 성적데이터를 반별로 나눈다음 / 다시 성별로 나누어 평균 점수를 구할 수 있다는 말이다.
# drv 와 class로 그룹을 짓고, 각 그룹 별 cty의 min()
mpg.groupby(['drv', 'class']).min()[['cty']]
# 데이터 만들기
test1 = pd.DataFrame({'id' : [1, 2, 3, 4, 5],
'midterm' : [60, 80, 70, 90, 95]})
test2 = pd.DataFrame({'id' : [1, 2, 3, 4, 5],
'final' : [70, 83, 65, 95, 80]})
데이터를 가로로 합칠때는 pd.merge()를 이용합니다. pd.merge(열1, 열2) 이 기본 모양이다. 여기서 만약 열1은 모두 살리고 싶다면 how = "left" 를 하고 공통되는 부분이 많다면 on = 데이터를 합칠 때 기준으로 삼을 변수명 을 표기해주는 게 좋다.
# test
total = pd.merge(test1, test2, how = 'left', on = 'id')
print(total)
# id midterm final
# 0 1 60 70
# 1 2 80 83
# 2 3 70 65
# 3 4 90 95
# 4 5 95 80
다른 데이터를 활용해 변수 추가하기도 가능하다
teacher = pd.DataFrame({'nclass' : [1, 2, 3, 4, 5],
'teacher' : ['kim', 'lee', 'park', 'choi', 'jung']})
exam_new = pd.merge(exam, teacher)
세로로 합치는 방법도 있다. pd.concat()에 결합할 데이터 프레임명을 [] 를 이용해 나열하면 된다.
pd.concat([test1, test2])
# id midterm final
# 0 0 60.0 NaN
# 1 1 80.0 NaN
# 2 2 70.0 NaN
# 3 3 90.0 NaN
# 4 6 95.0 NaN
# 0 1 NaN 70.0
# 1 2 NaN 83.0
# 2 3 NaN 65.0
# 3 5 NaN 95.0
# 4 7 NaN 80.0
결과를 보면 알겠지만 열2가 열1의 아래에 그냥 붙는 것을 알 수 있다. 만약 굳이 axis=1 을 추가하여 옆에 붙인다고 해도
print(pd.concat([test1, test2], axis=1))
# id midterm id final
# 0 0 60 1 70
# 1 1 80 2 83
# 2 2 70 3 65
# 3 3 90 5 95
# 4 6 95 7 80
이런식으로.. 공통되는 부분(id) 마저 그대로 살아 옆에 그냥 붙어 있는 것을 확인 할 수 있다. join 옵션도 있는데.
print(pd.concat([test1, test2], join = 'inner'))
# id
# 0 0
# 1 1
# 2 2
# 3 3
# 4 6
# 0 1
# 1 2
# 2 3
# 3 5
# 4 7
이런식으로 사용할 수 있다.
# 문제를 하나 풀어보자
# test2의 final 컬럼명을 midterm 으로 바꾸고 test3라고 명명해라
test3 = test2.rename({'final':'midterm'}, axis=1)
# 만들어진 test3와 test1을 붙여라. 기준열은 test1이다
group_test = pd.concat([test1, test3])
# id 별로 group_test의 평균값을 구해라
group_test.groupby('id')['midterm'].mean()
group_test.groupby('id').agg(mean_t = ('midterm', 'mean'))
group_test.groupby('id').agg(np.mean)
# 먼저 사용해줄 결측치를 만들자
exam.iloc[[0, 1, 2], [2, 3, 4]] = np.nan
결측치 확인을 위해서는 pd.isna() 를 사용할 수 있다. 결측치는 True, 결측치가 아닌 값은 False로 표시해 데이터를 출력한다.
df = exam.copy()
pd.isna(df).sum()

결측치 빈도를 확인하고 싶으면 .sum()을 사용해주면 된다.
pd.isna(df).sum()
# id 0
# nclass 0
# math 3
# english 3
# science 3
# dtype: int64
결측치를 제거하기 위해서는 .dropna(subset = ) 을 사용해 줄 수 있다.
# 만약 수학 열에 있는 결측치만 제거하고 싶다면
df.dropna(subset='math')
# 모든 변수에서 결측치가 없는 행만 추출한다
df.dropna()
+) 각각의 칼럼에 대해서 평균값 구해보기
# apply all columns
df.apply(np.mean)
# id 10.500000
# nclass 3.000000
# math 58.470588
# english 83.352941
# science 58.882353
# dtype: float64
결측치가 너무 많거나 데이터가 작을 때 결측치가 있는 값들을 제거 시 너무 많은 데이터가 손실되어 분석 결과가 왜곡되는 문제가 생길 수 있다.
평균으로 결측치를 대체하려면 fillna() 를 이용할 수 있다. 괄호 안에 대체할 값을 입력하면 된다.
# 수학열을 수학열의 평균으로 채우겠다
m = df['math'].mean()
df['math'] = df['math'].fillna(m)
# 과학열을 과학열의 평균값으로 채우겠다면
df['science'].fillna(df['science'].mean(), inplace=True)
# 만약 english NaN 이 있다면 55로 대체하겠다
df['english'] = df['english'].fillna(55)
# bfill로 할경우 결측값을 바로 아래 값과 동일하게 변경하겠다
df['english'].fillna(method = 'bfill', inplace=True)
fillan는 DataFrame에서 결측값을 원하는 값으로 변경하는 메서드이다.
# 기본 사용법
df.fillna(value= , method=, axis= , inplace= , limit=, downcast=)
value : 결측값을 대체할 값. dict 형태로도 가능하다
method : 결측값을 변경할 방식이다
- bfill : 결측값을 바로 아래 값과 동일하게 변경
- ffill : 결측값을 바로 위 값과 동일하게 변경
axis : (0:index/1:columns) fillna 메서드를 적용할 레이블
inplace : 원본을 변경할지 여부
limit : 결측값을 변경할 횟수. 위에서부터 limit로 지정된 갯수만큼 변경한다.
지정값이 없으면 None이 기본으로 전체 다 변경된다.
downcast : 다운캐스트를 할것인지 묻습니다.
ex) downcast='infer'일 경우 float64를 int64로 변경한다.
이상치는 정상 범위에서 크게 벗어난 값을 뜻한다. 오류는 아니지만 분석 결과가 왜곡 될 수 있으므로 분석에 앞서 이상치를 제거하는 것이 좋다.
import pandas as pd
# 예제로 사용할 데이터
# 1,2 중 한 번호로 이루어져있어야하는 sex 변수
# 1~5 중 한 번호로 이루어져있어야하는 num 변수
df = pd.DataFrame({'sex' : [1, 2, 1, 3, 2, 1],
'num' : [5, 4, 3, 4, 2, 6]})
df.value_counts()를 이용해 빈도표를 출력해보면 이상치를 확인할 수 있다.
df['sex'].value_counts().sort_index()
# 1 3
# 2 2
# 3 1
# Name: sex, dtype: int64
df['num'].value_counts().sort_index()
# 2 1
# 3 1
# 4 2
# 5 1
# 6 1
# Name: num, dtype: int64
보면 예상하지 못한 값이 끼어있는 것을 확인 할 수 있다. 이 이상치를 결측치로 처리하려면 np.where 을 이용할 수 있다. 이상치일 경우 NaN 처리를 하는 것이다.
import numpy as np
df['sex'] = np.where(df['sex'] == 3, np.nan, df['sex'])
df['num'] = np.where((1 <= df['num'])&(df['num'] <= 5), np.nan, df['num'])
# 빈도수 출력해보기
df['sex'].value_counts().sort_index()
# 1.0 3
# 2.0 2
# Name: sex, dtype: int64
df['num'].value_counts().sort_index()
# 2.0 1
# 3.0 1
# 4.0 2
# 5.0 1
# Name: num, dtype: int64
반환하는 값 중 문자가 있으면 np.nan 을 이용하더라도 결측치 NaN이 아니라 nan 이 반환된다.
df = pd.DataFrame({'x1' : [1, 2, 1, 1]})
df['x2'] = np.where(df['x1'] == 1, 'a', np.nan)
print(df.isna())
# x1 x2
# 0 False False
# 1 False False
# 2 False False
# 3 False False
문자 nan 이 된 값을 .replace를 이용해 NaN으로 변경해 주어야 정상적으로 결측치 처리가 된다
df['x2'] = df['x2'].replace('nan', np.nan)
print(df.isna())
# x1 x2
# 0 False False
# 1 False True
# 2 False False
# 3 False False
& 혹은 | 연산자를 사용하여 다중 조건 구현. 각 조건을 괄호 쌍으로 묶고 그 사이에 & 연산자를 사용하는 것이다.
arr = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
arr[np.where((arr>3) & (arr<8))]
알트키를 누른 상태로 입력하려는 문자에 해당하는 값을 누른 다음 알트키에서 손을 떼면 된다. 예를 들어서
Alt + 183 = ·
Alt + 133 = …
와 같이 사용할 수 있는 것인데. 해당하는 값은 흔히 아스키 코드(정확히는 아니라고 하지만)이다.
더 많은 코드들을 확인하고 싶다면 이 페이지를 참고해도 재미있을 듯