PYTHON DATA 시각화 – PANDAS #1

pandas 를 사용한 기본 도식화

pandas 는 많은 절차를 자동화해 도식화를 매우 쉽게 해준다. 도식화는 내부적으로 Matplotlib에 의해 처리된다.

  • 그릴 수 있는 도면 -- 선 -- 막대 -- 상자 -- 산포도 -- 커널 밀도 추정(KDE, Kernel Density Estimates) -- 히스토그램
In [1]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
In [2]:
df = pd.DataFrame(index=['Atiya','Abbas','Cornelia','Stephanie','Monte'],
                  data={'Apples':[20,10,40,20,50],
                        'Oranges':[35,40,25,19,33]})

df
Out[2]:
Apples Oranges
Atiya 20 35
Abbas 10 40
Cornelia 40 25
Stephanie 20 19
Monte 50 33

1. bar plot 그리기

In [3]:
color=['.2','.7']
ax = df.plot.bar(color=color,figsize=(16,4))
ax.get_figure().savefig('c13-pdemo-bar1.png')

2. KDE plot

인덱스를 무시하고 열 이름을 x축을 따라 사용하고 열 값을 y축을 따라 확률 밀도를 계산하는 데 사용한다.

In [4]:
ax = df.plot.kde(color=color,figsize=(16,4))
ax.get_figure().savefig('c13-pdemo-kde1.png')

3. line, scatter, bar plot

하나의 figure 에 line, scatter, bar 차트 그리기

In [5]:
fig, (ax1, ax2, ax3) = plt.subplots(1,3,figsize=(16,4))
fig.suptitle("†wo Variable Plots", size=20, y=1.02)
df.plot.line(color=color, ax=ax1, title='Line Plot')
df.plot.scatter(x='Apples', y='Oranges', ax=ax2, title='Scatter Plot')
df.plot.bar(color=color, ax=ax3, title='Bar Plot')
fig.savefig('c13-pdemo-scat.png')

4. KDE, 상자그림, 히스토그램 plot

하나의 figure 에 KDE, 상자그림, 히스토그램 넣기

In [6]:
fig, (ax1, ax2, ax3) = plt.subplots(1,3,figsize=(16,4))
fig.suptitle("One Variable Plots", size=20, y=1.02)
df.plot.kde(color=color, ax=ax1, title='KDE plot')
df.plot.box(ax=ax2, title='Boxplot')
df.plot.hist(color=color, ax=ax3, title='Histogram')
fig.savefig('c13-pdemo-kde2.png')

5. 열 지정 후 시각화

x 나 y 값에 사용하려는 정확한 열을 지정을 하거나 데이터 정렬 후 시각화 한다.

In [7]:
fig, (ax1, ax2, ax3) = plt.subplots(1,3, figsize=(16,4))
df.sort_values('Apples').plot.line(x='Apples', y='Oranges', ax=ax1)
df.plot.bar(x='Apples', y='Oranges', ax=ax2)
df.plot.kde(x='Apples', ax=ax3)
Out[7]:
<AxesSubplot:ylabel='Density'>

6. flights 데이터 시각화

우회, 취소, 연착, 정시 운행된 항공편을 계산 데이터를 보면 DIVERTED : 후회 CANCELLED : 취소 DELAY : 예정보다 15분을 넘게 도착(ARR_DELAY)

In [8]:
flights = pd.read_csv('data/flights.csv')
flights
Out[8]:
MONTH DAY WEEKDAY AIRLINE ORG_AIR DEST_AIR SCHED_DEP DEP_DELAY AIR_TIME DIST SCHED_ARR ARR_DELAY DIVERTED CANCELLED
0 1 1 4 WN LAX SLC 1625 58.0 94.0 590 1905 65.0 0 0
1 1 1 4 UA DEN IAD 823 7.0 154.0 1452 1333 -13.0 0 0
2 1 1 4 MQ DFW VPS 1305 36.0 85.0 641 1453 35.0 0 0
3 1 1 4 AA DFW DCA 1555 7.0 126.0 1192 1935 -7.0 0 0
4 1 1 4 WN LAX MCI 1720 48.0 166.0 1363 2225 39.0 0 0
... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
58487 12 31 4 AA SFO DFW 515 5.0 166.0 1464 1045 -19.0 0 0
58488 12 31 4 F9 LAS SFO 1910 13.0 71.0 414 2050 4.0 0 0
58489 12 31 4 OO SFO SBA 1846 -6.0 46.0 262 1956 -5.0 0 0
58490 12 31 4 WN MSP ATL 525 39.0 124.0 907 855 34.0 0 0
58491 12 31 4 OO SFO BOI 859 5.0 73.0 522 1146 -1.0 0 0

58492 rows × 14 columns

DELAYED, ON_TIME column 을 생성해준다

In [9]:
cols = ['DIVERTED','CANCELLED', 'DELAYED']
(
    flights
        .assign(DELAYED=flights['ARR_DELAY'].ge(15).astype(int),
                   ON_TIME=lambda df_: 1 - df_[cols].any(axis=1))
        .select_dtypes(int)
        .sum()

)
Out[9]:
MONTH          363858
DAY            918447
WEEKDAY        229690
SCHED_DEP    81186009
DIST         51057671
SCHED_ARR    90627495
DIVERTED          137
CANCELLED         881
DELAYED         11685
ON_TIME         45789
dtype: int64
In [10]:
fig, ax_array = plt.subplots(2, 3, figsize=(18,8))
(ax1, ax2, ax3), (ax4, ax5, ax6) = ax_array
fig.suptitle('2015 US Flights - Univariate Summary', size=20)
ac = flights['AIRLINE'].value_counts()
ac.plot.barh(ax=ax1, title='Airline')

(
    flights['ORG_AIR'].value_counts().plot.bar(ax=ax2, rot=0, title='Origin City')
)

(
    flights['DEST_AIR'].value_counts().head(10).plot.bar(ax=ax3, rot=0, title='Destination City')
)

(
    flights.assign(DELAYED=flights['ARR_DELAY'].ge(15).astype(int),
                   ON_TIME=lambda df_: 1 - df_[cols].any(axis=1))
    [['DIVERTED','CANCELLED','DELAYED','ON_TIME']].sum()
    .plot.bar(ax=ax4, rot=0, log=True, title='Flight Status')
)

flights['DIST'].plot.kde(ax=ax5, xlim=(0,3000), title='Distance KDE')

flights['ARR_DELAY'].plot.hist(ax=ax6, title='Arrival Delay', range=(0,200))
fig.savefig('c13-uni1.png')

6-1 flights 를 주별 데이데 시각화(resample 함수)

flights 데이터는 MONTH, DAY 값이 정의 되어 있다. SCHED_DEP의 컬럼을 이용하여 HOUR, MINUTE 의 컬럼을 정의 할 수 있다.

In [11]:
df_date = (
    flights[['MONTH','DAY']]
    .assign(YEAR=2015,
            HOUR=flights['SCHED_DEP'] // 100,
            MINUTE=flights['SCHED_DEP'] % 100)
)

flights_dep = pd.to_datetime(df_date)
In [13]:
flights.index = flights_dep
fc = flights.resample('W').size()
fc.plot.line(figsize=(12,3), title='Flights per Week', grid=True)
fig.savefig('c13-ts1.png')

6-2 보간법을 사용해 누락된 데이터 처리

10월에 대한 데이터가 누락 되었다. 첫 주와 마지막 주도 평소보다 낮은데, 7일이 꽉 찬 완전한 주가 아닐 수 있기 때문일 수도 있다.

600편 미만의 비행이 있는 주는 결측치로 만들고, 보간법을 사용해 누락된 데이터를 채운다.

In [19]:
def interp_lt_n(df_, n=600):
    return (df_
            .where(df_ > n)
            .interpolate(limit_direction='both')
    )

fig, ax = plt.subplots(figsize=(16,4))
data = (flights
        .resample('W')
        .size())

(data
 .pipe(interp_lt_n)
 .iloc[1:-1]
.plot.line(color='black', ax=ax)
)

mask = data < 600

(data
 .pipe(interp_lt_n)
 [mask]
.plot.line(color='.8', linewidth=10)
)

ax.annotate(xy=(.8, .55), xytext=(.8, .77), xycoords='axes fraction', s='missing data', ha='center', size=20, arrowprops=dict())
ax.set_title('Flights per Week (Interpolated Missing Data)')
fig.savefig('c13-ts2.png')
/Users/kimseongmog/opt/anaconda3/envs/statics/lib/python3.7/site-packages/ipykernel_launcher.py:26: MatplotlibDeprecationWarning: The 's' parameter of annotate() has been renamed 'text' since Matplotlib 3.3; support for the old name will be dropped two minor releases later.

6-3 평균 항로가 가장 긴 공항

  • 인입 항공편의 평균 항로가 가장 긴 공항
  • 최소 100개의 전체 항공편
In [21]:
fig, ax = plt.subplots(figsize=(16,4))
(flights
 .groupby('DEST_AIR')
 ['DIST']
.agg(['mean','count'])
 .query('count > 100')
 .sort_values('mean')
 .tail(10)
 .plot.bar(y='mean', rot=0, legend=False, ax=ax, title='Average Distance per Destination')
 )
fig.savefig('c13-var1.png')

6-4 산포도 그리기

2,000 마일 미만의 모든 비행에서 거리와 비행시간 사이의 산포도 그리기

In [23]:
fig, ax = plt.subplots(figsize=(8,6))
(flights
 .reset_index(drop=True)
 [['DIST','AIR_TIME']]
 .query('DIST <= 2000')
 .dropna()
 .plot.scatter(x='DIST',y='AIR_TIME',ax=ax, alpha=.1, s=1)
)

fig.savefig('c13-scat1.png')
In [24]:
flights[['DIST','AIR_TIME']].corr()
Out[24]:
DIST AIR_TIME
DIST 1.00000 0.98774
AIR_TIME 0.98774 1.00000

6-5 cut 함수를 이용하여 그룹 으로 만들기

거리와 운행 시간 사이에 선형 관계가 존재하지만 마일 수가 중가함에 따라 분산도 증가하는것이 보인다. cut 함수를 사용해 비행 거리를 8개의 그루으로 만든다.

In [28]:
(flights
 .reset_index(drop=True)
 [['DIST','AIR_TIME']]
 .query('DIST<=2000')
 .dropna()
 .pipe(lambda df_:pd.cut(df_.DIST, bins=range(0,2001, 250)))
 .value_counts()
 .sort_index()
 )
Out[28]:
(0, 250]         6529
(250, 500]      12631
(500, 750]      11506
(750, 1000]      8832
(1000, 1250]     5071
(1250, 1500]     3198
(1500, 1750]     3885
(1750, 2000]     1815
Name: DIST, dtype: int64

6-6 각 그룹 내 평균 운항 시간에서 벗어난 표준편차 구하기

In [30]:
zscore = lambda x: (x-x.mean()) / x.std()
short = (flights
         [['DIST','AIR_TIME']]
         .query('DIST<=2000')
         .dropna()
         .reset_index(drop=True)
         .assign(BIN=lambda df_:pd.cut(df_.DIST,bins=range(0,2001,250)))
)

scores = (short
          .groupby('BIN')
          ['AIR_TIME']
          .transform(zscore)
)

(short.assign(SCORE=scores))
Out[30]:
DIST AIR_TIME BIN SCORE
0 590 94.0 (500, 750] 0.490966
1 1452 154.0 (1250, 1500] -1.267551
2 641 85.0 (500, 750] -0.296749
3 1192 126.0 (1000, 1250] -1.211020
4 1363 166.0 (1250, 1500] -0.521999
... ... ... ... ...
53462 1464 166.0 (1250, 1500] -0.521999
53463 414 71.0 (250, 500] 1.376879
53464 262 46.0 (250, 500] -1.255719
53465 907 124.0 (750, 1000] 0.495005
53466 522 73.0 (500, 750] -1.347036

53467 rows × 4 columns

6-7 상자그림을 통하여 이상치 발견

In [35]:
fig, ax = plt.subplots(figsize=(10,6))
(short.assign(SCORE=scores).pivot(columns='BIN')['SCORE'].plot.box(ax=ax))
ax.set_title('Z-Score for Distance Groups')
fig.savefig('c13-box2.png')

6-8 6표준편차 보다 큰 데이터 확인

In [37]:
mask = (short.assign(SCORE=scores).pipe(lambda df_:df_.SCORE.abs()>6))
outliers = (flights
            [['DIST','AIR_TIME']]
            .query('DIST <= 2000')
            .dropna()
            .reset_index(drop=True)
            [mask]
            .assign(PLOT_NUM=lambda df_:range(1, len(df_)+1))
)
outliers
Out[37]:
DIST AIR_TIME PLOT_NUM
14972 373 121.0 1
22507 907 199.0 2
40768 643 176.0 3
50141 651 164.0 4
52699 802 210.0 5

6-9 scatter plot 에서 이상치와 같이 그리기

In [38]:
fig, ax = plt.subplots(figsize=(8,6))
(short
 .assign(SCORE=scores)
 .plot.scatter(x='DIST',y='AIR_TIME', alpha=.1, s=1, ax=ax, table=outliers)
)

outliers.plot.scatter(x='DIST',y='AIR_TIME', s=25, ax=ax, grid=True)

outs = outliers[['AIR_TIME','DIST','PLOT_NUM']]
for t, d, n in outs.itertuples(index=False):
    ax.text(d+5, t+5, str(n))

plt.setp(ax.get_xticklabels(), y=.1)
plt.setp(ax.get_xticklines(), visible=False)
ax.set_xlabel('')
ax.set_title('Flight Time vs Distance with Outliers')
fig.savefig('c13-scat3.png', dpi=300, bbox_inches='tight')

답글 남기기

이메일 주소는 공개되지 않습니다.