Programming/Python

Python 기초 공부 - 8 (Pandas,numpy)

Joon09 2021. 3. 9. 18:19
반응형
%matplotlib inline
import mglearn
import matplotlib.pyplot as plt
mglearn.plots.plot_scaling()

정규화
표준편차를 구하는 이유 : 중심으로부터 이격이 얼마나 있는가를 확인하기 위해
분석에서는 분산이 커야 주성분 (분산이 크면 왜 이런 분포인지, 어떻게 줄일 수 있는지 연구대상이 됨)
z-score (관측치-평균)/표준편차
표준화 => 표준정규분포 (확률)

 

import pandas as pd
import numpy as np
df = pd.DataFrame([[1, np.nan, 2],[2,3,5],[np.nan,4,6]])
df

df.dropna()

df.dropna(axis='columns')

df[3] = np.nan
df.dropna(axis='columns', how='all') #모두가 nan이면 없애라

data = pd.Series([1, np.nan, 2, None, 3], index=list('abcde'))
data

a    1.0
b    NaN
c    2.0
d    NaN
e    3.0
dtype: float64

data.fillna(0)

a    1.0
b    0.0
c    2.0
d    0.0
e    3.0
dtype: float64

data.fillna(method='ffill') #forward fill

a    1.0
b    1.0
c    2.0
d    2.0
e    3.0
dtype: float64

data.fillna(method='bfill') #backward fill

a    1.0
b    2.0
c    2.0
d    3.0
e    3.0
dtype: float64

import missingno as msno
import matplotlib.pyplot as plt
import pandas as pd
df = pd.read_csv('diab.csv', header=None)
msno.matrix(df)
plt.show()

msno.bar(df) # na의 존재를 시각화해서 확인
plt.show()

df.dropna()

df = pd.DataFrame({'value':np.random.randint(0,100,20)})
print(df)

labels = ["{0}-{1}".format(i, i+9) for i in range(0, 100, 10)]
print(labels)
# 0, 10, 20, ... 100
df['group'] = pd.cut(df.value, range(0, 105, 10), right=False, labels=labels) # 문자열 라벨을 이용해 범주화
# rigth = False : 오른쪽 끝은 제외

    value
0      31
1      57
2      73
3      67
4      51
5      97
6      21
7      50
8      51
9      71
10     96
11     10
12     71
13     15
14     18
15     65
16     97
17     65
18     32
19     74
['0-9', '10-19', '20-29', '30-39', '40-49', '50-59', '60-69', '70-79', '80-89', '90-99']

 

범주화

# 범주화
raw_cat = pd.Categorical(['a','b','c','a'], categories=['b','c','d'], ordered=False)
raw_cat

[NaN, b, c, NaN]
Categories (3, object): [b, c, d]



원핫인코딩

# 원핫인코딩 : 선형회귀에서 범주형 변수는 반드시 실행
# 연속형 + 범주형
df = pd.DataFrame({'key':['b','b','a','c','a','b'],
                  'data1':range(6)})
pd.get_dummies(df['key'])

from pandas import Series, DataFrame # 메모리에서 이점이 있는 import 방식 (원하는 것만 로딩)
# dict키는 중복안됨
# DataFrame = dict + 중복을 허용하고 순서를 보장
df1 = DataFrame({'key':['b','b','a','c','a','a','b'],
                'data1':range(7)})
print(df1)

  key  data1
0   b      0
1   b      1
2   a      2
3   c      3
4   a      4
5   a      5
6   b      6

 

df2 = DataFrame({'key':['a','b','d'], 'data2':range(3)})
print(df2)

  key  data2
0   a      0
1   b      1
2   d      2

 

print(pd.merge(df1, df2, how='inner')) # 있는 것만!

  key  data1  data2
0   b      0      1
1   b      1      1
2   b      6      1
3   a      2      0
4   a      4      0
5   a      5      0

 

print(pd.merge(df1, df2, on='key')) # 키값 일치

  key  data1  data2
0   b      0      1
1   b      1      1
2   b      6      1
3   a      2      0
4   a      4      0
5   a      5      0

 

print(pd.merge(df1, df2, left_on='key', right_on='key')) # 키이름이 다를때는 이렇게 사용

  key  data1  data2
0   b      0      1
1   b      1      1
2   b      6      1
3   a      2      0
4   a      4      0
5   a      5      0

 

print(pd.merge(df1, df2, how='outer')) # 일치하지 않는 것도 다

  key  data1  data2
0   b    0.0    1.0
1   b    1.0    1.0
2   b    6.0    1.0
3   a    2.0    0.0
4   a    4.0    0.0
5   a    5.0    0.0
6   c    3.0    NaN
7   d    NaN    2.0

 

# 인덱스 이름 : 계층적 인덱스를 생성
data = DataFrame(np.arange(6).reshape(2,3), index=pd.Index(['Ohio','Colorado'], name='state'),
                columns=pd.Index(['one','two','three'], name='number'))
print(data)

number    one  two  three
state                    
Ohio        0    1      2
Colorado    3    4      5

 

result = data.stack() # 데이터를 재정비해서 내가 원하는 타입으로 만들기 위해서 / r 에서는 melt
print("분리")
print(result)

분리
state     number
Ohio      one       0
          two       1
          three     2
Colorado  one       3
          two       4
          three     5
dtype: int32

 

print(result.unstack())

number    one  two  three
state                    
Ohio        0    1      2
Colorado    3    4      5

 

# 데이터 중복
data = pd.DataFrame({'k1':['one']*3 + ['two']*4,
                    'k2':[1,1,2,3,3,4,4]})
print(data)
print("중복")
print(data.duplicated())
print(data.drop_duplicates()) #원본을 제거하는 게 아님
data1 = data.drop_duplicates()
data['v1']=range(7)
print(data)

    k1  k2
0  one   1
1  one   1
2  one   2
3  two   3
4  two   3
5  two   4
6  two   4
중복
0    False
1     True
2    False
3    False
4     True
5    False
6     True
dtype: bool
    k1  k2
0  one   1
2  one   2
3  two   3
5  two   4
    k1  k2  v1
0  one   1   0
1  one   1   1
2  one   2   2
3  two   3   3
4  two   3   4
5  two   4   5
6  two   4   6

 

data.drop_duplicates(['k1','k2'], keep='last')

data.drop_duplicates(['k1','k2']) # 포인터에 의해서 전달하기 때문에 list 형태로 전달함

data = Series([1., -999., 2., -999., -1000., 3.])
print(data)

0       1.0
1    -999.0
2       2.0
3    -999.0
4   -1000.0
5       3.0
dtype: float64

 

print("특정 데이터를 nan으로", data.replace(-999, np.nan))
print("변경", data.replace([-999, -1000], np.nan))
print("짝으로", data.replace([-999, -1000], [np.nan,0]))
print(data.replace({-999:np.nan, -1000:0})) # 키 데이터 형식으로 지정

특정 데이터를 nan으로 0       1.0
1       NaN
2       2.0
3       NaN
4   -1000.0
5       3.0
dtype: float64
변경 0    1.0
1    NaN
2    2.0
3    NaN
4    NaN
5    3.0
dtype: float64
짝으로 0    1.0
1    NaN
2    2.0
3    NaN
4    0.0
5    3.0
dtype: float64
0    1.0
1    NaN
2    2.0
3    NaN
4    0.0
5    3.0
dtype: float64

 

문제

# 문제
data = DataFrame(np.arange(12).reshape((3,4)),
                index=['Ohio','Colorado','New York'],
                columns=['one','two','three','four'])
# index의 단어를 모두 대문자로 변경하시오
data.index = data.index.str.upper()
data.index = data.index.map(str.upper)
data

# Title : titlecase 첫자만 대문자
# https://light-tree.tistory.com/108
data.rename(index=str.title, columns=str.upper)
# 특정 인덱스 수정하고 싶을 때
data.rename(index={'OHIO':'Indiana'}, columns={'three':'peekaboo'})

import pandas as pd
import numpy as np
from numpy import array
# 다음 데이터를 18~25, 25~35, 35~60, 60~100 사이의 값으로 범주화하시오
# 나으 풀이
ages = [20,22,25,27,21,24,37,31,61,45,41,32]
labels = ['18-25', '25-35', '35-60', '60-100']
range_list = [18, 25, 35, 60, 100]
age_group = pd.cut(ages, range_list, right=False, labels=labels)
# default는 true (right 값이 포함)
age_group
df = DataFrame(ages, age_group)
df

# 쌤의 풀이
ages = [20,22,25,27,21,24,37,31,61,45,41,32]
bins = [18, 25, 35, 60, 100]
cats = pd.cut(ages, bins)
cats # 범주화한 데이터
# 범주화 => 숫자로 매핑, 종류별로 숫자화
print("code", cats.codes) # 확인은 codes로 할 수 있음
print("범주의 종류는", cats.categories)

code [0 0 0 1 0 0 2 1 3 2 2 1]
범주의 종류는 IntervalIndex([(18, 25], (25, 35], (35, 60], (60, 100]],
              closed='right',
              dtype='interval[int64]')

 

# 범주별로 도수분포표를 작성하시오
print("범주별로 카운트 한 결과", pd.value_counts(cats))

범주별로 카운트 한 결과 (18, 25]     5
(35, 60]     3
(25, 35]     3
(60, 100]    1
dtype: int64

 

# 예제
def cut(array, bins, labels, closed='right'):
    _bins = pd.IntervalIndex.from_tuples(bins, closed=closed)

    x = pd.cut(array, _bins)
    x.categories = labels
    return x

 

array = [3.5, 1, 0.5, 3]
bins = [(0,1), (1,2), (3,4)]
labels = ['first', 'second', 'third']

df = pd.DataFrame({
    'value': array,
    'category': cut(array, bins, labels, closed='right')
})
df 

 

 

 

다음 데이터를 로딩하고, 문제를 푸시오

path ="./olive.csv"
df = pd.read_csv(path)
df.head(5) # 기본 3형제, 데이터만 보면 자동으로 나와야 함
print(df.dtypes)
df.describe()

olive.csv
0.03MB

Unnamed: 0     object
region          int64
area            int64
palmitic        int64
palmitoleic     int64
stearic         int64
oleic           int64
linoleic        int64
linolenic       int64
arachidic       int64
eicosenoic      int64
dtype: object

1) 첫번째 컬럼 이름을 ID_area로 지정하시오.

df.rename(columns={df.columns[0]:'ID_area'}, inplace=True)
df.columns #컬럼만 확인
df.head()

2) regions의 값들을 중복하지 않고 몇 개의 범주인지 확인하시오.


df.region.unique()
df.area.unique()
# crosstab : 교차분석표
pd.crosstab(df.area, df.region)

3) 처음 컬럼(ID_area)에 들어온 이상한 숫자를 제거하시오.


# 데이터 하나에 대해서 어떻게 처리할지만 정해서 apply 해주면 됨!
df["ID_area"] = df["ID_area"].apply(lambda x: x.split('.')[1])

4) 산성관련성분인 'palmitic', 'palmitoleic', 'stearic', 'oleic', 'linoleic'
'linoenic', 'arachidic', 'eicosenoic'의 컬럼만 추려서 별도의 sub데이터 프레임(변수이름 dfsub)을 생성하시오.


acidlist = ['palmitic', 'palmitoleic', 'stearic', 'oleic', 'linoleic', 'linolenic', 'arachidic', 'eicosenoic']
dfsub = df[acidlist]
dfsub.head()

 

5) dfsub의 데이터를 모두 100으로 나누어 소수점으로 나타내시오.


#dfsub = dfsub/100 요래 해도 되고 ( 다 숫자데이터라 가능함 )
dfsub = df[acidlist].apply(lambda x: x/100) # apply & lambda 함수에 익숙해져야함!
df[acidlist] = dfsub # 계산한 결과 반영
dfsub.head()

6) palmitic산과 linolenic산의 분포도를 시각화하시오.


fig = plt.figure()
plt.scatter(df['palmitic'], df['linolenic'])
axis = fig.gca()
axis.set_title('linolenic vs palmitic')
axis.set_xlabel('palmitic')
axis.set_ylabel('linolenic')

Text(0, 0.5, 'linolenic')

7) groupby를 활용하여 region을 기준으로 묶어서 region_groupby 객체로 생성


region_groupby =df.groupby(['region'])
region_groupby.mean()
# 다른방법 apply 사용(1)
region_groupby.apply(np.mean) # 함수의 주소를 넘겨줌
# 참고 : 여러 함수 적용 시 aggFunc

 

 

또 다른 방법 apply 사용(2)


region_groupby.apply(lambda x : x.mean()) # x가 시리즈 ()를 붙여서 실행시킴

8) region_groupby에 describe() 메소드 적용하여 출력해보시오.


region_groupby.describe()

 

 

반응형