본문 바로가기
AI 컴퓨터 비전프로젝트

[Python] 판다스(pandas) 데이터 프레임 합치기,산술연산, 원핫인코딩 등

by 바다의 공간 2024. 6. 18.

1. 데이터 프레임 행 합치기

이번에는 df1 과 df2의 데이터를 합쳐보았습니다.

df2는 임의로 작성한 연봉과 가족수를 넣은 자료들입니다.

 

일단 df1는 따로 copy를 따놓고 df_copy라는 이름으로  해두었습니다.

 

행을 합치는 매소드 concat을 이용하여서 데이터를 합쳐보겠습니다.

pd.concat([df1, df_copy])  (사실 같은 파일)

여기서 기본값은 axis = 0(행)이기때문에 밑으로 합쳐지게 됩니다.

이러면 인덱스가 0~19, 0~19가 있고 이것이 행으로 합쳐지게 됩니다.

인덱스가 겹치니 인덱스를 새롭게 적용하고 싶어집니다.

이럴때 사용 할 수 있는 매소드는

reset_index() : 새롭게 인덱스를 적용하기 

입니다.

변수하나로 다시 담아놓고

df_concat = pd.concat([df1, df_copy])
df_concat.reset_index()

로 진행했습니다.

이렇게되면 기존 인덱스와 새로운 인덱스 둘 다 표시되게 됩니다.

이럴때 drop으로 삭제해야하지만, 다른방법으로는 drop=True라는 옵션을 이용할 수 있습니다.

df_concat.reset_index(drop=True)

를 하게되면 

index 컬럼은 사라지고 새롭고 가지런한 index만 남게 됩니다.


2. 데이터 프레임 열 합치기

이번에는 열로 데이터를 합쳐보려고 합니다.

pd.concat([df1, df2], axis=1)

여기서 보면 같은 index 끼리 합쳐진다는점을 알아야합니다.

여기서는 df1과 df2의 인덱스에있는 이름을 맞춰서 저장했기떄문에 깔끔하게 합쳐진것을 확인할 수 있습니다.


인덱스를 기준으로 데이터가 합쳐지는것 증명하기

인덱스가 다르면 데이터 합칠때 엉키기때문에  인덱스도 잘 확인을 해야하고

어떻게 엉키는지 확인하기 위해서 정리했습니다.

 

확인해보기 위해 인덱스를 일부러 삭제하겠습니다.

인덱스를 삭제하기 위해서는 drop이라는 매소드를 이용할 수 있고

df3에 dr2의 1,3,5,7 행을 drop한 값을 넣어보겠습니다.

 

df3= df2.drop([1,3,5,7])

df3

df3

라는 결과가 나오고 이 데이터를 다시 합치면

pd.concat([df1, df3], axis=1)

삭제한 인덱스 값에 대한 자료는 NaN처리가 된것을 확인할 수 있습니다.


그다음 일단!

새롭게 df_right라는 변수를 만들고 출력해보았습니다.

df_right = df2.drop([1,3,5,7,9], axis=0)
dr_right

사라진 값에 대해서 다시 index를 재정리하고싶습니다.  

df_right = df_right.reset_index(drop=True)
df_right

이렇게 되면 인덱스가 재정리 됩니다.

이 데이터를 가지고 다시 합쳐보겠습니다.

pd.concat([df1, df_right], axis=1)

결과를 확인할 수 있습니다.


하지만 인덱스를 기준으로 데이터를 합치기에는 인덱스가 숫자가 아닐 경우도 있으니 

확실한 기준을 가지고 합칠 수 있는 매소드를 사용하면 좋습니다.

그것은 바로 merge()입니다.

 

merge(): 특정 고유한 키(uniqe, id)값을 기준으로 합침

사용방법 :

merge(데이터프레임1, 데이터프레임2, on='유니크값', how='병합의 기준') 을 작성하면 됩니다.

병합의 기준은 : left, right, inner, cross입니다.

pd.merge(df1, df_right, on='이름', how='left')

이름이라는 공통을 기준으로 왼쪽 (df1)에 모든 데이터를 뿌려줘~ 라는 뜻입니다.

즉 이름 기준으로 합쳐달라고 하고 빠진 값이 있으면 NaN으로 출력됩니다.

pd.merge(df1, df_right, on='이름', how='right')

오른쪽 기준으로 정렬이 되고 오른쪽에 데이터가 있는 사람들이 나오게 됩니다. 그러다보니 20개였던 데이터들이 날라가고 14개만 남는것을 볼 수 있습니다.


pd.merge(df1, df_right, on='이름', how='inner')   #교집합


새로운 데이터를 넣어 확인하기

임의로 김사과 라는 자료를 넣어보겠습니다.

dic = {
    '이름':'김사과',
    '연봉': 9000,
    '가족수':10
}
pd.merge(df1, df_right, on='이름', how='left')

를 출략헤보면 김사과는 나오지 않습니다. 이유는 김사과는 right에 대한 자료이기때문에 left를 한다고 하더라도

표시되지 않습니다.

pd.merge(df1, df_right, on='이름', how='right')

right로 변경해서 출력을 해보면 

 

이렇게 되면 자료가 나오게 됩니다.

pd.merge(df1, df_right, on='이름', how='inner')   #교집합

inner를 했을떄는 NaN자료가 빠지니 김사과도 빠진 데이터프레임만 출력되게 됩니다.


3. cross

-모든 데이터를 다 합쳐보는 매소드

모든 경우의 수를 다 합쳐보는 매소드 입니다

pd.merge(df1, df_right, how='cross')

이렇게 320rows와 11columns를 곱한 값이 나오게 됩니다.


이름이 다른 경우에 합쳐보기

left_on, right_on이라는 속성을 이용하면 됩니다.

df_right.columns = ['성함', '연봉', '가족수']
df_right

 

pd.merge(df1, df_right, left_on='이름', right_on='성함', how='right')


4. 등수 매기기

rank() : 데이터프레임 또는 시리즈의 순위를 매기는 함수, 기본값은 ascending입니다.

파생변수 : 변수와 변수를 이용해서 다른 변수로 파생된 변수를 파생변수라고 합니다.

ascending:상승적인(a)

df1['브랜드순위'] = df1['브랜드평판지수'].rank()
df1

이렇게되면 브랜드 순위가 20이 아니라 1이 되어야되는데 그러려면  ascending=False를 해주면 됩니다.

 

df1['브랜드순위'] = df1['브랜드평판지수'].rank(ascending=False)
df1

그런데 여기서 보면 브랜드 순위를 굳이 float로 할 필요가 없으니  int로 바꿔주도록 하겠습니다.

특정열의 자료형을 변경할때에는 

astype()을 사용해서 특정열의 자료형을 변경해주면 됩니다.

지금같은경우에는 브랜드순위를 int로 변경하면 됩니다.

df1['브랜드순위']=df1['브랜드순위'].astype(int)
df1

마지막으로 브랜드순위의 type을 확인하려면 dtypes를 사용해서 확인해보면 됩니다.

df1['브랜드순위'].dtype
 
dtype('int64')

결과는 int64로 잘 변환 되었다는걸 확인할 수 있습니다.


5. 날짜타입 사용하기

판다스에는 데이터타입중에 날짜타입이 있습니다. 

날짜를 저장하는 타입인데, object형으로 저장하면되는데 왜 굳이 날짜타입이 필요하냐면 날짜계산을 하기 위해서입니다.

요일, 날짜 등을 확인할 수 있습니다. 

 

 

df.info

 

이 중에서 날짜로 볼 수 있는것은 'birthday'정도입니다.

 

 

df['birthday']

이 정보는 문자열이기때문에 object형입니다. 이것을 문자열로 바꿔보려고 합니다.

*to_datetime(): object타입에서 datetime타입으로 변환

 

df['birthday'] =pd.to_datetime(df['birthday']
df['birthday']

datetime으로 변환딥니다.

*datetime64로 변경되었을때 사용할 수 있는 기능들

#년도확인
df['birthday'].dt.year
#월 확인
df['birthday'].dt.month
#일수 확인
df['birthday'].dt.day
#시간이 있다면 시간형태로 데이터뽑기 가능
df['birthday'].dt.hour

 

#분 
df['birthday'].dt.minute

#초 
df['birthday'].dt.second

#요일
df['birthday'].dt.dayofweek
#0: 월요일~~~~6:일요일
#1년중에 몇번쨰 주인지 확인하기
df['birthday'].dt.isocalendar().week

6.apply 사용하기

- Series나 DataFrame에 구체적인 로직을 적용하고 싶을 때 사용합니다.

- apply를 적용하기 위해서는 별도의 함수를 먼저 정의해야합니다.

- 작성된 함수를 apply에 매개변수로 전달합니다(callback)

df.head()

#성별이 남자는 1, 여자는 0으로 변환(loc를 사용)
df.loc[df['gender'] == '남자', 'gender'] = 1
df.loc[df['gender'] == '여자', 'gender'] = 0

이렇게되면 남자인 성만 추출되고 남자는 1 여자는 0으로 변경됩니다.

df.head()

확인결과


다음 초기화를 시키고 같은 내용을 함수로 넣어보았습니다.

 

def male_or_female(x):
    if x =='남자':
        return 1
    elif x == '여자':
        return 0
    else:
        return None
df['성별'].apply(male_or_female)

성별을 뽑아서 .apply로 등록하면 callback을 하게되니 모든 행에서 실행하고 적용시켜줍니다.

(단 저장은되지않음)

위 함수는 한번쓰고 잘 사용하지 않기때문에 굳이 함수말고 

이름없는 익명함수로 실행하면 더 효율적이기때문에 람다함수로 변경해줍니다.

df['성별'].apply(lambda x:1 if x == '남자' else 0)

이렇게 해도 같은 값이 나옵니다.


이제 함수를 저장하려고 합니다. 파생변수를 넣을겁니다.

df['New성별'] = df['성별'].apply(lambda x: 1 if x == '님지' else 0)
df.head()

그럼 파생변수로 New성별이 들어가고 남자는1 여자는 0으로 보이게 됩니다.


15. map 사용하기

딕셔너리를 통해서 데이터와 같은 키의 값을 적용시켜주는 매서드입니다.

map_gender = {'남자':1, '여자':0}
df['성별'].map(map_gender)

 

남자는0 ,여자는 1로 변경되는걸 확인할 수 있습니다.

그럼 이것또한 파생변수로 New성별로 넣어서 출력해보면

df['New성별']= df['성별'].map(map_gender)
df.head()

우측에 파생변수가 생긴것을 확인할 수 있습니다.


데이터프레임의 산술연산

말 그대로 데이터프레임의 연산을 할 수 있습니다.

df = pd.DataFrame({
    '파이썬':[60,70,80,90,95],
    '데이터분석':[40,60,70,55,87],
    '머신러닝딥러닝':[35,40,30,70,55]
})

이렇게 각각 파이썬, 데이터분석, 머신러닝딥러닝에 대한 점수를 df에 입력을 하고

인덱스는 자동으로 만들어지고 column 값은 key,value값이 됩니다.

파이썬의 dtype은 데이터프레임 열 의데이타 타입을 나타내는것이기때문에 int입니다.

df['파이썬'].dtypes
#출력
dtype('int64')

타입이라는 함수를 써서 파이썬을 확인해보면 series가 나오게 됩니다.

그 시리즈가 모여서 데이터프레임이 되는거구요.

type(df['파이썬'])

#출력
pandas.core.series.Series

이제 산술연산을 해보려고 합니다.

df['파이썬'] + df['데이터분석'] +df['머신러닝딥러닝']

 파이썬,데이터분석, 머신러닝딥러닝의 값을 합치게 되면 

가 출력되게 됩니다.


실습문제1.

df에 총점, 평균이라는 파생변수를 만들고 파생변수에 총점, 평균을 구해서 저장해라.

df['총점'] =df['파이썬'] + df['데이터분석'] +df['머신러닝딥러닝']

df['평균'] = df['총점']/3


 

df['파이썬'].sum()

 #df['파이썬'].sum(axis=0)이 생략된것이라고 볼 수 있습니다.

이렇게 합쳐지게 되므로 값은 395가 출력됩니다.

df['파이썬'].mean()

평균은 79가 됩니다. == (60+70+80+90+95)/3 == 79

df.sum()

df.mean()

sum mean

각 시리즈마다 열이 합쳐지고 평균이 나는것을 확인할 수 있습니다.


df1 = pd.DataFrame({
    '파이썬':[60,70,80,90,95],
    '데이터분석':[40,60,70,55,87],
    '머신러닝딥러닝':[35,40,30,70,55]
})

df2 = pd.DataFrame({
    '파이썬':['C', 'B', 'B', 'A', 'A'],
    '데이터분석':[40,60,70,55,87],
    '머신러닝딥러닝':[35,40,30,70,55]
})

여기서 df1과 df2를 더하면 error가 뜹니다.

이유는 각 포지션끼리의 연산인데 df2의 값은 문자로 되어있기때문에 더할 수 없습니다.

df1 + 10


df1 = pd.DataFrame({
    '데이터분석':[40,60,70,55,87],
    '머신러닝딥러닝':[35,40,30,70,55]
})

df2 = pd.DataFrame({
    '데이터분석':[40,60,70,55],
    '머신러닝딥러닝':[35,40,30,70]
})
df1 + df2

여기서는 error가 나지 않습니다.그 이유는 빠진데이터는 알아서 자동으로 NaN처리 해주기 때문입니다.


17. select_dtypes

df

df데이터를 넣고 info를 확인해보니

df.info()

여기서 object column 의 데이터만 가져오고싶을때는

df.select_dtypes(include='object')

여기서 보면 키, 브랜드평판지수로 된 숫자형은 빠지게 된것을 볼 수 있습니다.

 

반대로

문자열을 뺸 컬럼만 가져오고싶을때는

df.select_dtypes(exclude='object')   #문자열 컬럼만 빼고 가져오기


조금 더 디테일하게 데이터를 다뤄보겠습니다.

문자가 아닌 컬럼에만 +10씩 더하고싶을 때는 

df.select_dtypes(exclude='object') + 10


문자열을 가지고 있는 컬럼의 이름만 변수에 저장하여 출력해보겠습니다.

str_cols = df.select_dtypes(include='object').columns
str_clos


내가 원하는 문자열 컬럼만 볼 수 있습니다.

df[str_cols]

 


18. 원 핫 인코딩(One Hot Encoding)

  • 원 핫 인코딩은 한개의 요소는1, 나머지 요소는 0으로 만들어 카테고리형을 표현하는 방법
  • 예) df['혈액형']
    • 머신러닝/딥러닝 알고리즘에 넣어서 데이터를 예측하려고 한다면 라벨인코딩을 하여 수치 데이터로 변환
    • 컴퓨터는 값의 관계를 스스로 형성하게 될 수 있음
    • 만약 B형은 1, AB형이 2라는 값을 가지고 있다면, 컴퓨터는 'B형 + AB형 = O형'이라는 이상한 관계를 맺을 수 있음
    • 따라서 별도의 column들을 형성해주고 1개의 column 1, 나머지 column에는 0으로 넣어줌으로 'A, B, AB, O형의 관계는 서로 독립적이다'라는 카테고리로 표현하는 방식

라벨인코딩을 하겠습니다.

blood_map = {'A':0, 'B':1, 'AB':2, 'O':3}
df['혈액형_code'] = df['혈액형'].map(blood_map) #라벨인코딩
df.head()


get.dummies라는 매소드를 활용해서 혈액형_code를 분할하겠습니다.

이것이 원 핫 인코딩입니다. 

예를들어 0번인덱스가  A형이라면 A는 True, 그 외 나머지는 False로 표현이 됩니다.

pd.get_dummies(df['혈액형'])

 


아래의csv에 적용해보겠습니다.

df = pd.get_dummies(df, columns=['혈액형'])
df


다시 정보를 확인해보면 아래와같은 결과를 볼 수 있습니다.

df.info()

 


이렇게 판다스를 활용한 데이터 다루기를 전체적으로 다뤄보았습니다.