pandas 개인과제 리뷰

안장훈·2024년 12월 24일

python 공부

목록 보기
4/6

저번주 금요일에 pandas 개인과제가 나왔다. 1~3번 밖에 풀지 못했지만 팀원들의 과제 리뷰와 함께 해설 강의를 함께 리뷰 해보자.

문제1. 데이터 조회, 정렬, 조건 필터

타이타닉 데이터는 타이타닉호 생존자, 사망자에 관한  데이터입니다.

컬럼 (column) 설명

  • survivied: 생존여부 (1: 생존, 0: 사망)
  • pclass: 좌석 등급 (1등급, 2등급, 3등급)
  • sex: 성별
  • age: 나이
  • sibsp: 형제 + 배우자 수
  • parch: 부모 + 자녀 수
  • fare: 좌석 요금
  • embarked: 탑승 항구 (S, C, Q)
  • class: pclass와 동일
  • who: 남자(man), 여자(woman), 아이(child)
  • adult_male: 성인 남자 여부
  • deck: 데크 번호 (알파벳 + 숫자 혼용)
  • embark_town: 탑승 항구 이름
  • alive: 생존여부 (yes, no)
  • alone: 혼자 탑승 여부

조건 :

  • 나이가 20살 이상 40살 미만인 승객
  • pclass가 1등급 혹은 2등급인 승객
  • 열(column)은 survived, pclass, age, fare 만 나오게 출력
  • 10개만 출력
  • 나의 풀이

조건1과 조건2에 해당하는 데이터로 필터링하고 해당 데이터를 조건3에서 주어진 4가지 컬럼으로만 추려서 10개 만 출력한다.

첫번쨰로 조건1을 (df['age']>=20) & (df['age']<40)으로 쓰고 조건2에서 pclass가 1등급 혹은 2등급인 승객을 찾기위해 .isin([1,2])을 사용해 (df['pclass'].isin([1,2]))으로 써준다음 다 합치면 상위 두가지 조건을 모두 필터링 한 데이터가 주어진다.

filtered_data = df[(df['age']>=20) & (df['age']<40) & (df['pclass'].isin([1,2]))]

두번쨰로 column을 survived, pclass, age, fare만 나오게 출력하면

filtered_data2 = filtered_data[['survived', 'pclass', 'age', 'fare']]

마지막으로 .head(10)으로 10개만 추출해주면 끝이다.

  • 다른분 의 풀이

팀원들의 풀이에서 나와 다른점은 다들 필터링을 한 후 컬럼을 지정하여 출력하는 과정에서 .loc를 사용해서 지정해준후 .reset_index()로 인덱스를 새로 지정해 주었다.
아무래도 필터링된 데이터를 깔끔하게 정리 해줄 필요가 있어 보인다.

문제2. 데이터 합치기 및 컬럼 생성

간단한 고객 데이터와 주문 데이터를 합치고, 주문여부에 따라 고객을 분류하고자 합니다.

  • 요구사항
    • 고객 테이블(customers)를 기준으로 주문 테이블(orders)를 합쳐주세요. 주문 금액이 없는 고객도 모두 포함되어야 합니다.
    • 주문 금액이 없는 경우, 0으로 표현하세요.
    • 주문금액이 있는 경우 "구매", 주문금액이 0인 경우 "미구매"로 분류하는 "구매여부" 칼럼을 생성하세요.
      • df출력 (결과칼럼: 고객번호, 이름, 금액, 구매여부)
  • 나의 풀이
import pandas as pd
import numpy as np

#고객 테이블
customers = pd.DataFrame({

    '고객번호': [1001, 1002, 1003, 1004, 1005, 1006, 1007],

    '이름': ['승철', '동경', '예나', '혜연', '장훈', '채운', '다연']

})

#주문 테이블

orders = pd.DataFrame({

    'cno': [1001, 1001, 1005, 1006, 1008, 1001],

    '금액': [10000, 20000, 15000, 5000, 100000, 30000]

})

위에 문제에서 주어진 두 테이블을 고객테이블을 기준으로 합친다음 결측치를 0으로 채워주고 주문금액에 따라 '구매','비구매'로 분류하여 "구매여부"컬럼을 추가해준다.

첫번째로 두 테이블을 고객기분으로 합쳐야 하는데 SQL에서는 left join을 사용하였지만 python에선 merge를 사용하여 한쪽 테이블 기준으로 합칠 수 있다.

result1 = customers.merge(orders1, how='left', left_on='고객번호', right_on='cno')

위와 같이 써주면 sql에서 사용한 join처럼 on으로 공통 칼럼을 지정해주듯이 left_on='고객번호', right_on='cno'으로 이어 줄수 있다. 그러면 'cno''고객번호'로 인식되어 겹쳐진다.

두번째로 결측치가 0으로 바뀌도록 .fillna(0)을 하면 결측치가 채워진다.
세번째는 구매여부를 분류하는 구매여부 칼럼을 만들어 주기위해 데이터 프레임에 함수처리를 하는 .apply()lambda를 사용하여 금액이 0이 아니면 '구매', 그 이외의 경우 '미구매'로 처리하고 분류된 항목을 '구매여부'컬럼으로 할당해주면 끝이다.

result1 = customers.merge(orders1, how='left', left_on='고객번호', right_on='cno')
result2 = result1.fillna(0)
result2['구매여부'] = result2['금액'].apply(lambda x: '구매' if x > 0 else '미구매')
result2 = result2[['고객번호', '이름', '금액', '구매여부']]
result2

이렇게 하면 완성이긴 한데 개인적으로 같은 구매자가 여러번 보이는게 싫어서 orders 테이블을 먼저groupby()로 묶어주었다.

orders1 = orders.groupby('cno', as_index=False)['금액'].sum()
result1 = customers.merge(orders1, how='left', left_on='고객번호', right_on='cno')
result2 = result1.fillna(0)
result2['구매여부'] = result2['금액'].apply(lambda x: '구매' if x > 0 else '미구매')
result2 = result2[['고객번호', '이름', '금액', '구매여부']]
result2


이렇게 하고 나서 보니 금액을int로 해줘서 정수처리 하는거랑 금액컬럼의 이름을 총금액으로 해줘야 되나 싶긴하다.

  • 정답 풀이
# 방법1
 orders.rename(columns = {'cno':'고객번호'}, inplace = True)
 df = pd.merge(customers, orders, on = "고객번호", how = "left")
# 방법2
 df = pd.merge(customers, orders, left_on = "고객번호", right_on = "cno", how = "left")
 df.drop(columns = "cno", inplace = True)
df['금액'] = df['금액'].fillna(0).astype(int)
df["구매여부"] = "구매"
df.loc[df["금액"]==0, "구매여부"] = "미구매"
#df["구매여부"] = np.where(df["금액"] > 0, "구매", "미구매")
df

먼저 두가지 방법으로 merge를 하는데 orders테이블에서 cnocustomers테이블과 같게 고객번호로 이름을 바꿔준후 합치는 방법이 있고 다음은 내가 한 것처럼 left_onright_on을 써주는데 추가로 .drop()으로 cno칼럼을 날려준다.
다음은 팀원들과 미리 리뷰했을때 나온 지적중에 정수로 변환 안한것이 있었는데 역시나 풀이에도 금액의 결측치 처리를 할때 astype(int)로 정수처리 해주는걸 볼수 있다.
마지막으로 구매여부 칼럼을 추가할때 구매를 디폴트 값으로 먼저 칼럼을 만들어준다음 .loc()금액이 0인 경우에 미구매로 처리되도록 한다.
추가로 numpy를 사용하여 df["구매여부"] = np.where(df["금액"] > 0, "구매", "미구매")로 조건을 걸어서 할수도 있다.

문제3. iris 데이터 활용

  • 배경
    • iris 데이터셋은 붓꽃(iris) 품종 중 Setosa, Versicolor, Virginica 분류에 대한 로널드 피셔의 1936년 논문에서 사용된 데이터 셋입니다.
    • 꽃받침(Sepal)과 꽃잎(Petal)의 길이 너비로 세개 품종을 분류하고 있습니다. 분류에 앞서, 꽃받침 넓이와 길이, 꽃잎의 넓이와 길이에 대한 기초 통계량을 확인하고자 합니다.
    • 가장 상관관계가 높은 변수가 무엇인지를 찾고, 이를 시각화하고자 합니다.
  • 요구사항
    • 3-1) species별 sepal length, sepal width, petal length, petal width의 평균과 표준편차를 구하세요.
    • 3-2) sepal length, sepal_width, petal_length, petal_width 4가지 변수 중 가장 상관관계가 높은 두 변수를 찾으세요.
    • 3-3) 위에서 구한 두 변수를 x,y축으로 두고 species에 따라 분류하는 산점도를 생성하세요.
  • 나의 풀이
import pandas as pd
import numpy as np
import seaborn as sns

iris= sns.load_dataset("iris")

3-1) 불러온 데이터셋에서 speciesgroupby()한 다음 agg(['mean', 'std'])으로 평균과 표준 편차를 구한다.

require1 = iris.groupby('species').agg(['mean', 'std'])

3-2) 4가지 변수의 상관관계를 분석하고 그중 가장 상관관계가 높은 변수 두개 를 찾는다.
이 문제는 구글링 하다가 풀이 과정이 어렵긴 한데 가장 쉽게 푸는거 같아서 열심히 배껴서 풀었다.
먼저 상관관계를 분석하기 위해서 .corr을 사용해야 하는데 그냥 하면 iris에 숫자열 이외의 정보도 있기 때문에 오류가 뜬다 그래서 numeric_iris = iris.select_dtypes(include=np.number)숫자열로 된 정보만 집은 데이터를 따로 만든다음 상관 계수를 구한다음

numeric_iris = iris.select_dtypes(include=np.number)
corr_iris = numeric_iris.corr()
corr_iris = corr_iris.apply(lambda x: round(x,2))
s = corr_iris.unstack()
df = pd.DataFrame(s[s < 1].sort_values(ascending=False), columns=['corr'])
max_corr = df.head(2)
print(f"가장 상관관계가 높은 두 변수: {max_corr}")

3-3) 3-2에서 구한 두 변수를 x,y축으로 두고 species에 따라 분류되도록 matplotlibimport 하여 scatterplot을 그린다.

0개의 댓글