Gorio Tech Blog search

seaborn 사용법(python seaborn 사용법)

|

이 글에서는 python seaborn의 사용법을 정리한다.

따로 명시하지 않으면 이 글에서의 예제 데이터는 다음으로 설정한다.

data = pd.DataFrame(data={
    'A': [1,4,3,6,5,8,7,9],
    'B': [6,5,7,8,9,9,8,9],
    'C': [8.8,7.7,6.6,5.5,4.4,3.3,2.2,1.1]
})

seaborn 설치

설치는 꽤 간단하다.

pip install seaborn

import는 관례적으로 다음과 같이 한다.

import seaborn as sns

막대 그래프(barplot)

sns.barplot(data=data)

그래프 배경 설정(set)

  • 기본값은 style="darkgrid"이고 darkgrid, whitegrid, dark, white, ticks 테마가 있다.
  • sns.set(style='darkgrid') 또는 sns.set_style('whitegrid')와 같이 사용한다.
sns.set() 
plt.scatter(x=data.index, y=data['A'])
sns.set_style('dark')
plt.scatter(x=data.index, y=data['A'])

Heatmap

sns.heatmap(data)

눈금 값 설정(xticks, yticks)

heatmap을 구성하는 각 box의 중심 좌표는 제일 왼쪽 아래가 (0.5, 0.5)이다. 즉 0.5만큼을 더해줘야 한다. 여기서 벗어나게 지정할 수도 있지만 이상해 보인다.

sns.heatmap(data)
plt.xticks([0.5, 1.5, 2.9], ["A class", "B class", "C class"])

데이터 값 표시(annot, fmt)

  • 데이터 값을 표시하려면 annot=True를 지정한다.
  • fmt 인자는 d, .2f와 같이 지정할 수 있다.
sns.heatmap(data, annot = True, fmt = ".2f")

선 스타일 설정

다른 그래프와 비슷하게 linewidth, linecolor로 설정할 수 있다.

sns.heatmap(data, annot = True, fmt = ".1f", linewidth = 2, linecolor = "black")

Colormap 설정

sns.heatmap(data, annot = True, fmt = ".2f", cmap = "Blues", linewidth = 1, linecolor = "black")

cmap은 아래 그림들을 참조하자.

위 그림은 아래 코드로 생성할 수 있다.

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt

cmaps = {}

gradient = np.linspace(0, 1, 256)
gradient = np.vstack((gradient, gradient))


def plot_color_gradients(category, cmap_list):
    # Create figure and adjust figure height to number of colormaps
    nrows = len(cmap_list)
    figh = 0.35 + 0.15 + (nrows + (nrows - 1) * 0.1) * 0.22
    fig, axs = plt.subplots(nrows=nrows + 1, figsize=(6.4, figh))
    fig.subplots_adjust(top=1 - 0.35 / figh, bottom=0.15 / figh,
                        left=0.2, right=0.99)
    axs[0].set_title(f'{category} colormaps', fontsize=14)

    for ax, name in zip(axs, cmap_list):
        ax.imshow(gradient, aspect='auto', cmap=mpl.cm.get_cmap(name))
        ax.text(-0.01, 0.5, name, va='center', ha='right', fontsize=10,
                transform=ax.transAxes)

    # Turn off *all* ticks & spines, not just the ones with colormaps.
    for ax in axs:
        ax.set_axis_off()

    # Save colormap list for later.
    cmaps[category] = cmap_list


References

  • https://matplotlib.org/3.7.1/tutorials/colors/colormaps.html
Comment  Read more

matplotlib 사용법(python matplotlib.pyplot 사용법)

|

이 글에서는 python matplotlib의 사용법을 정리한다.

따로 명시하지 않으면 이 글에서의 예제 데이터는 다음으로 설정한다.

data = pd.DataFrame(data={
    'A': [1,4,3,6,5,8,7,9],
    'B': [6,5,7,8,9,9,8,9],
    'C': [8.8,7.7,6.6,5.5,4.4,3.3,2.2,1.1]
})

matplotlib 설치

설치는 꽤 간단하다.

pip install matplotlib

import는 관례적으로 다음과 같이 한다.

from matplotlib import pyplot as plt
import numpy as np
import pandas as pd

Font 설정

아무 설정을 하지 않으면 한글이 깨지는 경우가 많다.

RuntimeWarning: Glyph 44256 missing from current font.
  font.set_text(s, 0.0, flags=flags)

보통 다음과 같이 설정해주면 된다.

from matplotlib import rcParams
rcParams["font.family"] = "Malgun Gothic"
rcParams["axes.unicode_minus"] = False

참고로 설정 가능한 폰트 목록을 확인하고 싶다면 다음 코드를 실행해 보자.

import matplotlib.font_manager
fpaths = matplotlib.font_manager.findSystemFonts()
font_names = []
for i in fpaths:
    f = matplotlib.font_manager.get_font(i)
    font_names.append(f.family_name)

print(font_names[:5])

for fn in font_names:
    if 'malgun' in fn.lower():
        print(fn)

Jupyter 전용 기능

다음 magic command를 사용사면 plt.show() 함수를 사용하지 않아도 그래프를 보여준다.

%matplotlib inline
plt.scatter(x=[1,2,3], y=[4,5,6])

보통의 환경이라면 plt.show() 함수를 사용해야 그래프가 보인다. PyCharm이라면 SciView 창에서 열린다.


그래프 종류

산점도(scatter)

plt.scatter(x=[1,2,3], y=[4,5,6])

선 그래프(plot)

plt.plot(data.index, data['B'])
# 하나만 입력하면 기본 index로 그려진다.
plt.plot(data['C']) 
# 한 번의 plot() 호출로 여러 개를 그릴 수 있다. 순서는 x, y, fmt 순으로 입력할 수 있다.
t = np.arange(0., 5., 0.2)
plt.plot(t, t, 'r--', t, t**2, 'bs-', t, t**3, 'g^-.')

plot()은 list나 DataFrame뿐 아니라 dictionary도 그래프로 나타낼 수 있다.

data_dict = {'x': [1, 2, 3, 4, 5], 'y': [2, 3, 5, 7, 11]}
plt.plot('x', 'y', data=data_dict)

막대 그래프(bar)

plt.bar(data.index, data['B'])

2개 그룹 동시 표시

stack해서 사용하는 방법은 다음과 같이 bottom 옵션을 사용한다.

p1 = plt.bar(data.index, data['B'], color='red', alpha=0.7)
p2 = plt.bar(data.index, data['C'], color='blue', alpha=0.7, bottom=data['B'])
# plot이 여러 개인 경우 plt.legend()는 그냥 넣으면 legend가 출력되지 않는다.

나란히 놓는 방법은 bar의 width 옵션과 x좌표를 조정하면 된다.

p1 = plt.bar(data.index-0.2, data['B'], color='red', alpha=0.7, width=0.4)
p2 = plt.bar(data.index+0.2, data['C'], color='blue', alpha=0.7, width=0.4)
plt.legend((p1, p2), ('B', 'C'), fontsize=12)

boxplot

x = np.random.normal(50, 5, 100)
plt.boxplot(x)

여러 boxplot을 한 번에 그리려면 리스트에 담아서 전달한다.

x1 = np.random.normal(15, 5, 500)
x2 = np.random.normal(10, 10, 100)
plt.boxplot([x1, x2])
plt.xticks([1, 2], ["x1", "x2"])

Histogram

구간 개수는 bins으로 설정한다.

x = np.random.normal(10, 2, 100)
plt.hist(x, bins=10)

Heatmap

matshow라는 함수가 있지만 이건 seaborn의 heatmap이 더 편하다.

pd.DataFrame.plot

  • pandas의 dataframe에서 .plot() method를 호출하면 바로 그래프를 그릴 수 있다.
    • 종류는 line, bar, barh, hist, box, scatter 등이 있다. barh는 수평 막대 그래프를 의미한다.
data.plot(kind='line')

좀 더 자세하게 설정할 수도 있다. 이 글에 있는 스타일 설정을 대부분 적용할 수 있다.

data.plot(kind = "bar", y = ["B", "C"], figsize = (10, 6),
    yticks=[0, 5, 10])

단 boxplot과 histogram은 y만 설정할 수 있다.


스타일 설정

더 많은 설정은 여기를 참고하자.

  • dashes 옵션으로 직접 dash line을 조작할 수 있다.
  • markevery 옵션으로 마커를 만들 샘플을 추출할 수 있다. 옵션값이 5(int)면 5개의 샘플마다, float이면 상대적 거리에 따라 추출한다.
  • visible 옵션으로 선을 안 보이게 할 수 있다.
  • fillstyle 옵션으로 마커를 채우는 방식을 설정할 수 있다. full, left, right, bottom, top, none 가능

format string(fmt)

색상, 마커, 선 스타일을 쉽게 지정할 수 있다.

plt.plot(data['A'], 'b.-', label='A')
plt.plot(data['B'], 'cv--', label='B') 
plt.plot(data['C'], 'm|:', label='C')
plt.legend()

색상(color)

plt.plot(data['B'], label='B', color='red')
plt.plot(data['C'], label='C', color='green')
plt.legend()
fmt color
b blue
g green
r red
c cyan
m magenta
y yellow
k black
w white

선 스타일(linestyle), 두께(linewidth)

  • 선 스타일은 linestyle parameter를 전달하며 기본값인 soliddashed, dotted, dashdot이 있다.
  • 선 두께는 linewidth로 설정하고 기본값은 1.5이다.
plt.plot(data['A'], label='A', linestyle='dashed', linewidth=2)
plt.plot(data['B'], label='B', linestyle='dotted', linewidth=3)
plt.plot(data['C'], label='C', linestyle='dashdot', linewidth=4)
plt.legend()
fmt linestyle
- solid
-- dashed
: dotted
-. dashdot

수치로 직접 지정할 수 있다. 참고로 (0, (1, 1))dotted, (0, (5, 5))dashed, (0, (3, 5, 1, 5))dashdot과 같다.

plt.plot(data['A'], label='A', linestyle=(0, (1,1)), linewidth=2)
plt.plot(data['B'], label='B', linestyle=(0, (4,1)), linewidth=3)
plt.plot(data['C'], label='C', linestyle=(0, (1,4)), linewidth=4)
plt.legend()

bar 스타일(width, color, linewidth)

bar의 두께를 설정할 수 있다. 각 데이터마다 다른 값을 주면 각각 다르게 설정할 수도 있다.

plt.bar(data.index, data['A'], width=0.4, color=["red", "blue", "green", "purple", "red", "blue", "green", "purple"], linewidth=2.5)

마커(marker)

각 data point마다 marker를 표시할 수 있다.

  • 점: ., 원: o, 사각형: s, 별: *, 다이아몬드: D, d
  • marker의 사이즈도 markersize parameter로 지정할 수 있다.
  • 산점도(scatter)의 마커 크기는 s parameter로 설정한다. 단 크기가 10배 차이난다.
plt.plot(data['A'], label='A', marker='o', markersize=4)
plt.plot(data['B'], label='B', marker='s', markersize=8)
plt.scatter(data.index, data['C'], label='C', marker='.', s=120, color='red')
plt.legend()
fmt marker 설명 fmt marker 설명
. point s square 사각형
, pixel 픽셀 p pentagon 오각형
o circle * star
v triangle_down 역삼각형 h hexagon1 육각형 1
^ triangle_up 삼각형 H hexagon2 육각형 2
< triangle_left 삼각형(왼쪽) + plus + 모양
> triangle_right 삼각형(오른쪽) x x x 모양
1 tri_down 삼각뿔(아래쪽) D diamond 다이아몬드
2 tri_up 삼각뿔(위쪽) d thin diamond 얇은 다이아몬드
3 tri_left 삼각뿔(왼쪽) | vline v line
4 tri_right 삼각뿔(위쪽) _ hline h line

더 많은 마커 옵션이 있다.

투명도(alpha)

데이터가 너무 많은 경우 투명도를 조절하면 좀 더 잘 보이게 할 수 있다.

import numpy as np
x = np.random.normal(0, 1, 16384)
y = np.random.normal(0, 1, 16384)
plt.scatter(x, y, alpha = 0.04, color='purple')

그래프 전체 설정

그래프 크기 설정

plt.figure(figsize=(6, 3))
plt.scatter(x=data.index, y=data['A'])

그래프 제목(title)

plt.scatter(x=data.index, y=data['A'])
plt.title("Gorio")

범례 설정(legend)

기본적으로 plot(label=...) 등으로 label을 등록하면, plt.legend()로 등록된 label들을 표시해주는 개념이다.

plt.scatter(x=data.index, y=data['A'], label='Gorio')
plt.legend()

legend 위치는 그래프를 가리지 않는 위치에 임의로 생성된다. 위치를 지정하려면 loc parameter를 설정한다.

plt.scatter(x=data.index, y=data['A'], label='Gorio')
plt.legend(loc='lower right')

가능한 옵션을 총 9개이다. left, center, right, upper left, upper center, upper right, lower left, lower center, lower right

참고로 loc=(0.5, 0.5)와 같이 직접 수치를 지정할 수도 있다. loc=(0.0, 0.0)은 왼쪽 아래, loc=(1.0, 1.0)은 오른쪽 위이다.

legend() 메서드에서도 label을 직접 등록하여 표시할 수 있다.

p1 = plt.bar(data.index-0.2, data['A'], color='red', alpha=0.7, width=0.4)
p2 = plt.bar(data.index+0.2, data['C'], color='blue', alpha=0.7, width=0.4)
plt.legend((p1, p2), ('A', 'C'), fontsize=12)

ncol 옵션으로 범례에 표시되는 텍스트의 열 개수를 지정할 수 있다.

p1 = plt.bar(data.index-0.2, data['A'], color='red', alpha=0.7, width=0.4, label='A')
p2 = plt.bar(data.index+0.2, data['C'], color='blue', alpha=0.7, width=0.4, label='C')
plt.legend(ncol=2)

각종 다양한 스타일을 지정할 수 있다.

p1 = plt.bar(data.index-0.2, data['A'], color='red', alpha=0.7, width=0.4, label='A')
p2 = plt.bar(data.index+0.2, data['C'], color='blue', alpha=0.7, width=0.4, label='C')
plt.legend(frameon=True, shadow=True, facecolor='inherit', edgecolor='green', borderpad=0.8, labelspacing=1.1)

더 자세한 설정은 여기에서 확인 가능하다.


x, y축 설정

축 제목(xlabel, ylabel)

plt.scatter(x=data.index, y=data['A'])
plt.xlabel("x axis")
plt.ylabel("y axis")

축 제목과 축 간 거리는 labelpad로 조정한다.

plt.plot(data.index, data['A'])
plt.xlabel("x axis", labelpad=20)
plt.ylabel("y axis", labelpad=-1)

폰트 설정도 할 수 있다.

font1 = {'family': 'serif',
         'color': 'b',
         'weight': 'bold',
         'size': 14
         }

font2 = {'family': 'fantasy',
         'color': 'deeppink',
         'weight': 'normal',
         'size': 'xx-large'
         }

plt.plot([1, 2, 3, 4], [2, 3, 5, 7])
plt.xlabel('x Axis', labelpad=15, fontdict=font1)
plt.ylabel('y Axis', labelpad=20, fontdict=font2)

축 범위 설정(xlim, ylim, axis)

각 함수를 호출하면 return value로 x축, y축, x 및 y축의 최솟값/최댓값을 얻을 수 있다.

plt.scatter(x=data.index, y=data['A'])
xmin, xmax = plt.xlim(left=0, right=10)
ymin, ymax = plt.ylim(bottom=0, top=10)
# 아래 한 줄로도 쓸 수 있다.
# xmin, xmax, ymin, ymax = plt.axis([0,10,0,10])

참고로 left, right, bottom, top 중 설정하지 않은 값은 데이터 최솟값/최댓값에 맞춰 자동으로 설정된다.

범위를 수치로 직접 설정하는 대신 그래프의 비율이나 scale을 조정할 수 있다.
scaled의 경우 다음과 같이 x축 간격과 y축 간격의 scale이 같아진다.

plt.scatter(x=data.index, y=data['A'])
xmin, xmax, ymin, ymax = plt.axis('scaled')
# (-0.35000000000000003, 8.450000000000001, 0.6, 9.4)

다음과 같은 옵션들이 있다: 'on' | 'off' | 'equal' | 'scaled' | 'tight' | 'auto' | 'normal' | 'image' | 'square'

눈금 값 설정(xticks, yticks)

ticks에 tick의 위치를 지정하고, labels에 원하는 tick 이름을 지정할 수 있다.

plt.scatter(x=data.index, y=data['A'])
plt.xticks(ticks=[0,3,6], labels=['zero', 'three', 'six'])
plt.ylim(bottom=0, top=10)

xticks나 yticks에 값을 1개만 주면 ticks parameter가 설정된다.

plt.scatter(x=data.index, y=data['A'])
plt.xticks([0,3,6])
plt.ylim(bottom=0, top=10)

참고로 막대그래프는 기본적으로 막대의 중심 좌표를 기준으로 계산하지만 align parameter를 주면 왼쪽 위치로 계산할 수 있다.

plt.bar(data.index, data['B'], align='edge')
plt.xticks([0,3,6], ['zero', 'three', 'six'])

그래프 저장(savefig)

plt.scatter(x=data.index, y=data['A'])
plt.savefig("gorio.png", dpi=300)

dpi는 dot per inch의 약자이다. 높을수록 해상도가 좋아지고 파일 크기도 커진다.


References

  • https://wikidocs.net/book/5011
  • https://matplotlib.org/stable/api/_as_gen/matplotlib.lines.Line2D.html
Comment  Read more

PyCharm 사용법 2 - 단축키

|

PyCharm(파이참)은 Jetbrains 사에서 제작 및 배포하는 유료/무료 프로그램이다.
Professional 버전은 돈을 주고 구입하거나, 학생이라면 학생 인증을 하고 무료로 사용할 수 있다.

글이 길기 때문에 사용법을 검색하고 싶다면 Ctrl + F 키를 누른 다음 검색해 보자.

기본적인 사용법 및 고급 기능은 PyCharm 사용법(파이참 설치 및 사용법)에서 확인하자.

알아둘 점

  • 단축키를 누를 때는 반드시 적힌 순서대로 눌러야 한다.
  • 또한 일반 1~0 숫자키 및 사칙연산 키와 numpad에 있는 키는 다르게 취급한다. 예를 들면 -numpad-로 각기 다르게 표시한다.
  • [1~5]와 같이 대괄호로 표시된 것은 이 중 하나를 눌러도 된다는 뜻으로 예시는 숫자 1 또는 2~5를 누를 때 효과가 조금씩 다르다.
  • ,로 표시된 경우는 , 전까지의 단축키를 누른 다음 , 이후 키를 따로 누를 수 있다. 예를 들어 Ctrl + NumPad*, [1~5]의 경우 Ctrl를 누른 채로 NumPad*키를 누른 다음, 손을 뗀 다음에 숫자 1을 눌러도 된다. 그리고 이 경우 NumPad*까지 누르고 PyCharm 제일 왼쪽 아래를 보면 다음 키를 누를 수 있는 옵션이 표시되어 있다.

2023.04.22 updated


코드 접기 및 펼치기(expand and collapse)

참고: https://www.jetbrains.com/help/rider/Code_Folding.html#folding_menu

설명 단축키
코드 블록 펼치기 / 접기 line number 옆에 있는 +-버튼
선택한 부분을 펼치기 Ctrl + +
선택한 부분을 접기 Ctrl + -
선택한 부분을 재귀적으로 펼치기 Ctrl + Alt + NumPad+
선택한 부분을 재귀적으로 접기 Ctrl + Alt + NumPad-
파일의 모든 코드 블록 펼치기 Ctrl + Shift + NumPad+
파일의 모든 코드 블록 접기 Ctrl + Shift + NumPad-
선택한 부분을 level 1~5 까지 코드 펼치기 Ctrl + NumPad*, [1~5]
파일의 모든 코드 블록을 level 1~5 까지 코드 펼치기 Ctrl + Shift + NumPad*, [1~5]

References

공식 홈페이지에서 더 자세한 사용법을 찾아볼 수 있다.

Comment  Read more

gspread 사용법(python gspread - google spreadsheet)

|

구글 스프레드시트는 어떤 결과 같은 것을 정리하기에 꽤 괜찮은 도구이다.
그렇다면 파이썬으로 실험한 결과를 스프레드시트에 자동 기록하게 한다면..?

이 글에서는 python gspread를 이용해 자동으로 구글 스프레드시트에 값을 기록하는 방법을 정리한다.

코드의 일부는 gspread docs에서 가져왔다.


gspread 설치

설치는 꽤 간단하다.

pip install gspread

권한 및 환경 설정

먼저 프로젝트를 생성한다.

구글 클라우드에 로그인을 한 다음에 프로젝트 만들기를 누른다.

아래 스크린샷처럼 프로젝트 이름을 마음대로 지정한다. 위치를 지정하고 싶으면 지정한 다음(선택), 만들기를 누른다.

그러면 프로젝트가 하나 만들어진다. 먼저, 위쪽의 검색 창에서 Google Drive API를 검색한다.

그리고 사용을 눌러 준다. 마찬가지로, Google Sheets API를 검색한 다음 사용을 클릭한다.

이제 API 및 서비스 > 사용자 인증 정보(영어라면 APIs & Services > Credentials) 페이지로 이동한 다음, 사용자 인증 정보 만들기 > 서비스 계정(Create credentials > Service account key)를 클릭한다. 설명을 보면 로봇 계정이라 되어 있다. python을 쓸 수 있을 것 같지 않은가?

서비스 계정 이름을 설정한다. 그러면 자동으로 계정 ID도 만들어지는데, 수정해도 상관없다.
아래의 계정 설명이나 액세스 권한 부여(2, 3)번은 선택사항으로 패스해도 된다. 제일 아래의 완료를 클릭한다.

그러면 서비스 계정이 하나 생성된 것을 볼 수 있다. 서비스 계정 관리(Manage service accounts)를 클릭해 준다.

아래 그림과 같이 3점 버튼을 누르고 키 관리(Manage Keys)를 클릭한다.

키 추가 > 새 키 만들기를 클릭한다. (ADD KEY > Create new key)

그리고 뜨는 창에서 JSON을 그대로 두고 만들기(Create)를 클릭한다.

그러면 json 파일이 하나 다운로드될 것이다. json 파일을 열어보면, 아래랑 비슷하게 생겼다.

{
    "type": "service_account",
    "project_id": "api-project-XXX",
    "private_key_id": "2cd … ba4",
    "private_key": "-----BEGIN PRIVATE KEY-----\nNrDyLw … jINQh/9\n-----END PRIVATE KEY-----\n",
    "client_email": "473000000000-yoursisdifferent@developer.gserviceaccount.com",
    "client_id": "473 … hd.apps.googleusercontent.com",
    ...
}

client_email key가 보일 것이다. 옆에 value로 자동 생성된 어떤 email 주소가 보일 것이다. 이 이메일 주소를, 이제 python으로 결과를 입력할 스프레드시트에 다른 사용자를 추가하듯이 사용자 추가를 하면 된다.

이제, 아까 그 json 파일을 아래 기본 경로에 둔다. 파일 이름도 service_account.json로 바꿔준다.

  • Linux: ~/.config/gspread/service_account.json
  • Windows: %APPDATA%\gspread\service_account.json

이제 테스트를 해 보자. 스프레드시트를 원하는 제목으로 하나 만든다. (필자는 제목을 gorio_test_spread으로 했다)
1번째 행, 1번째 열(A1 셀)에 텍스트를 아무거나 입력하고(gspread test와 같은), 아래 코드를 python으로 실행시켜보자.

import gspread

gc = gspread.service_account()
sh = gc.open("gorio_test_spread") # 스프레드시트 제목으로 설정할 것

print(sh.sheet1.get('A1'))

# 결과: [['gspread test']]

참고로, 기본 권한 파일은 위의 기본 경로에 저장된 service_account.json이고, 다른 파일(즉, 다른 권한을 가진 계정 등)을 쓰려면 아래와 같이 쓰면 된다.

import gspread

gc = gspread.service_account(filename='C:/rnsrnbin_gorio_test_spread.json')
sh = gc.open("gorio_test_spread") # 스프레드시트 제목으로 설정할 것

print(sh.sheet1.get('A1'))

service account는 credential을 사용하거나 dictionary 형태로 받을 수 있다.

from google.oauth2.service_account import Credentials

scopes = [
    'https://www.googleapis.com/auth/spreadsheets',
    'https://www.googleapis.com/auth/drive'
]

credentials = Credentials.from_service_account_file(
    'path/to/the/downloaded/file.json',
    scopes=scopes
)

gc = gspread.authorize(credentials)

또는

import gspread

credentials = {
    "type": "service_account",
    "project_id": "api-project-XXX",
    "private_key_id": "2cd … ba4",
    "private_key": "-----BEGIN PRIVATE KEY-----\nNrDyLw … jINQh/9\n-----END PRIVATE KEY-----\n",
    "client_email": "473000000000-yoursisdifferent@developer.gserviceaccount.com",
    "client_id": "473 … hd.apps.googleusercontent.com",
    ...
}

gc = gspread.service_account_from_dict(credentials)

sh = gc.open("Example spreadsheet")

print(sh.sheet1.get('A1'))

credential과 관련해 더 자세한 내용은 여기를 참조하면 된다. 사실 위의 내용과 거의 같은 내용도 포함한다.


gspread 사용법

Spreadsheet open, create, share

권한과 환경설정을 모두 마쳤으면, 스프레드시트를 불러올 차례가 되었다.

스프레드시트는 시트의 제목, 또는 url로부터 고유 id를 가져오거나, 그냥 url 전체를 복붙하면 된다.

sh = gc.open('gorio_test_spread')
sh = gc.open_by_key('1kXGuatJwOmkMAat38UZ7OLdGBjt3HS1AobTGmlOuDns')
sh = gc.open_by_url('https://docs.google.com/spreadsheets/d/1kXGuatJwOmkMAat38UZ7OLdGBjt3HS1AobTGmlOuDns/edit#gid=0')

단, 제목으로 하면 같은 제목을 가진 스프레드시트가 여러 개 있을 경우에 그냥 마지막으로 수정된 시트가 열린다. 가능하면 url이라도 쓰자.

스프레드시트는 다음과 같이 생성할 수 있다.

sh = gc.create('A new spreadsheet')

공유하는 방법도 어렵지 않다.

sh.share('otto@example.com', perm_type='user', role='writer')

Sheet select, create, delete

가장 많이 쓰는 경우는 첫 번째 시트를 선택하는 경우이므로 아예 따로 지정되어 있다. 물론 다른 방법으로도 선택 가능하다.

worksheet = sh.sheet1

worksheet 번호로 선택할 수 있다. 물론 번호는 0부터 시작한다.

worksheet = sh.get_worksheet(0)

시트 제목으로 선택할 수도 있다.

worksheet = sh.worksheet("Gorio")

전체 시트 목록을 얻으려면 다음과 같이 하면 된다.

worksheet_list = sh.worksheets()

worksheet를 추가하거나 삭제하는 법도 간단하다.

# 추가
worksheet = sh.add_worksheet(title="New gorio worksheet", rows=50, cols=26)
# 삭제
sh.del_worksheet(worksheet)

셀 값 얻기

특정 1개의 셀 값을 얻는 방법은 여러 가지가 있다.

# 1행 3열의 셀 값 얻기
val = worksheet.cell(1, 3).value
val = worksheet.acell('C1').value
val = worksheet.get('C1') # 사실 get은 범위 연산도 가능하다. 출력되는 결과를 보면 2차원 리스트로 조금 다르게 생겼다.
# 결과:
# 'MR-full-mAP'
# 'MR-full-mAP'
# [['MR-full-mAP']]


# cell formula를 사용하는 방법도 있다.
cell = worksheet.acell('C1', value_render_option='FORMULA').value  # 또는
cell = worksheet.cell(1, 3, value_render_option='FORMULA').value # 1행 3열 -> C1

특정 행이나 열 전체의 셀 값을 가져올 수 있다.

values_list = worksheet.row_values(1)
values_list = worksheet.col_values(1)

이외에도 범위를 지정해서 셀 값을 가져올 수 있다.

  • get_all_values()는 worksheet 전체의 값을 가져온다.
  • get()는 지정한 범위의 셀 값을 전부 가져온다.
  • batch_get()는 1번의 api call로 여러 범위의 셀 값을 가져올 수 있다.
  • update()는 값을 가져오는 것이 아니라 원하는 값으로 셀을 수정할 수 있다.
  • 이제 batch_update()는 무슨 함수인지 알 것이다.

참고로 api call을 너무 많이 날리면 429 RESOURCE_EXHAUSTED APIError가 뜰 수 있다. 그래서 위에 소개한 범위 함수를 잘 쓰는 것이 중요하다.

api call limit은 다음과 같다.

  • 한 프로젝트당, 60초간 300회
  • 1명의 유저당, 60초간 60회

worksheet의 모든 값을 list의 list 또는 dict의 list 형태로 가져올 수 있다.

list_of_lists = worksheet.get_all_values()
list_of_dicts = worksheet.get_all_records()

셀 값 찾기

기본적으로, 셀은 다음과 같은 값들을 attribute로 갖는다.

value = cell.value
row_number = cell.row
column_number = cell.col

특정 문자열을 가지는 셀을 하나 또는 전부 찾는 방법은 아래와 같다.

cell = worksheet.find("Gorio")
print("'Gorio' is at R%sC%s" % (cell.row, cell.col))

# 전부 찾기
cell_list = worksheet.findall("Gorio")

정규표현식을 사용할 수도 있다.

amount_re = re.compile(r'(Big|Enormous) dough')
cell = worksheet.find(amount_re)

# 전부 찾기
cell_list = worksheet.findall(amount_re)

셀 값 업데이트하기

먼저, 선택한 범위의 셀 내용을 지우는 방법은 다음과 같다.

# 리스트 안에 요소로 셀 범위나 이름을 부여한 named range를 넣을 수 있다.
worksheet.batch_clear(["A1:B1", "C2:E2", "named_range"])

# 전체를 지울 수도 있다.
worksheet.clear()

특정 1개 또는 특정 범위의 셀을 지정한 값으로 업데이트할 수 있다.

worksheet.update('B1', 'Gorio')

# 1행 2열, 즉 B1
worksheet.update_cell(1, 2, 'Gorio')

# 범위 업데이트
worksheet.update('A1:B2', [[1, 2], [3, 4]])

서식 지정

셀 값을 단순히 채우는 것 말고도 서식을 지정할 수도 있다.

# 볼드체로 지정
worksheet.format('A1:B1', {'textFormat': {'bold': True}})

여러가지 설정을 같이 할 수도 있다. dict에 원하는 값을 지정하여 업데이트하면 된다.

worksheet.format("A2:B2", {
    "backgroundColor": {
      "red": 0.0,
      "green": 0.0,
      "blue": 0.0
    },
    "horizontalAlignment": "CENTER",
    "textFormat": {
      "foregroundColor": {
        "red": 1.0,
        "green": 1.0,
        "blue": 1.0
      },
      "fontSize": 12,
      "bold": True
    }
})

어떤 서식을 지정할 수 있는지는 여기를 참고하자.

또한, 셀 서식뿐만 아니라 워크시트의 일부 서식을 지정할 수도 있다.

예를 들어 행 또는 열 고정은 다음과 같이 값을 얻거나 지정할 수 있다.

get_frozen_row_count(worksheet)
get_frozen_column_count(worksheet)
set_frozen(worksheet, rows=1)
set_frozen(worksheet, cols=1)
set_frozen(worksheet, rows=1, cols=0)

셀의 높이나 너비를 지정하거나 데이터 유효성 검사, 조건부 서식 등을 지정할 수도 있다.

설치 방법 및 사용법은 다음을 참고하자.

  • https://gspread-formatting.readthedocs.io/en/latest/

numpy, pandas와 같이 사용하기

워크시트 전체를 numpy array로 만들 수 있다.

import numpy as np
array = np.array(worksheet.get_all_values())

# 시트에 있는 header를 떼고 싶으면 그냥 [1:]부터 시작하면 된다.
array = np.array(worksheet.get_all_values()[1:])

물론 numpy array를 시트에 올릴 수도 있다.

import numpy as np

array = np.array([[1, 2, 3], [4, 5, 6]])
worksheet.update('A2', array.tolist())

워크시트 전체를 불러와 pandas dataframe으로 만들고 싶으면 다음과 같이 쓰면 된다.

import pandas as pd
dataframe = pd.DataFrame(worksheet.get_all_records())

dataframe의 header와 value를 전부 worksheet에 쓰는 코드 예시는 다음과 같다.

import pandas as pd
worksheet.update([dataframe.columns.values.tolist()] + dataframe.values.tolist())

더 많은 기능은 다음 github을 참고하자.

  • https://github.com/aiguofer/gspread-pandas
  • https://github.com/robin900/gspread-dataframe

References

  • https://docs.gspread.org/en/latest/oauth2.html#enable-api-access
  • https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/cells#cellformat
  • https://gspread-formatting.readthedocs.io/en/latest/
Comment  Read more

AGQA 2.0 - An Updated Benchmark for Compositional Spatio-Temporal Reasoning 설명

|

이번 글에서는 AGQA 2.0: An Updated Benchmark for Compositional Spatio-Temporal Reasoning 논문을 정리한다.


Abstract

  • AGQA 1.0에서는 언어적 편향의 영향을 줄이기 위해 균형 잡힌 답변 분포로 훈련/테스트 분할을 제공하였다.
  • 그러나 여전히 편향성(bias)이 일부 남아 있다.
  • 2.0 benchmark에서는 몇 가지 개선 사항, 특히 더 엄격한 balancing이 적용되었다.
  • 그리고 모든 실험에 대해 업데이트된 benchmark 결과를 report한다.

1. Action Genome Question Answering

AGQA는 bias를 많이 없앤 좋은 VQA benchmark이지만 부족한 점이 여전히 있었다. 그래서 본 논문에서 2.0 버전으로 업그레이드한 버전을 소개하고자 한다. 언어적 편향성(language bias)을 더욱 제거할 수 있는 더 강력한 balancing 작업을 진행하여 총 96.85M개의 QA 쌍에서 2.27M쌍의 균형잡힌 데이터셋을 만들었다.

Section 2에서는 1.0과 2.0의 차이를, Section 3에서는 기존 모델들의 달라진 성능 체크를 report한다. balanced 버전에서는 어떤 모델도 이지선다형 질문에 51%의 정확도를 넘지 못했다.


2. Updates to AGQA

2.0에서는 특히 balancing 과정에 신경을 많이 썼다. 이전의 balancing 작업 역시 bias를 많이 없애기는 하였으나 여전히 남아 있는 bias를 모델들이 활용하였다.

  • balancing algorithm은 (다지선다형에서) 각 정답의 비율이 동일하도록 조정한다. 즉 특정 종류의 질문의 대답이 yes/no라면 yes가 50%, no도 50%의 비율로 나타나도록 한다.
  • Temporal localization phrases를 다루는 category definition도 재정의했다.
  • 결과적으로 HCRN의 경우 yes/no 질문에서 1.0에서는 72.12%의 정답률을 보였지만 bias를 제거한 2.0에서는 50.10%밖에 달성하지 못했다.

이외에도 작은 upgrade들이 있었다:

  1. relationship type을 명시하지 않고 object의 존재 여부를 물을 때 contactingtouching 용어를 interacts with로 바꾸었다. 이는 actor가 object를 물리적으로 “touch”하지 않아도 답변이 yes가 될 수 있음을 의미한다. 또한 doorway 상호작용은 불명확하므로 제거하였다.
  2. 종종 모호할 수 있는 간접적인 표현을 제거하였다. the thing they were doing to <object>와 같은 간접 관계 표현은 동치인 직접 관계 표현으로 바꾸기 애매하다. 또한 the object they held before running와 같이 temporal localization phrases와 관련한 object에 대한 간접 표현도 제거하였다.
  3. temporal localization phrases를 쓰려면 적어도 한 개의 annotated frame이 영상 안에 존재해야 하는 조건을 추가하였다. What did they do before running?와 같은 질문을 생성하려면 running 정보가 있는 frame이 적어도 하나는 존재해야 한다. (역자: 당연한 거긴 하지만)
  4. 간접표현에서 backward 용어가 잘못 사용된 것을 forward로 수정하였다.
  5. GT answer를 일반적인 단어인 action으로 대체함으로써 What action were they doing the longest?와 같이 최상급 표현으로 된 action에 대한 program을 개선하였다.
    • 가장 긴 action이 sitting인 영상 하나를 생각하자.
    • What was the person doing for the longest amount of time? 프로그램은
    • Superlative(max, Filter(video, [actions]), Subtract(Query(end, sitting), Query(start, sitting)))에서
    • Superlative(max, Filter(video, [actions]), Subtract(Query(end, action), Query(start, action)))으로 바뀌었다.
  6. 질문의 추론 단계를 최대 8단계로 제한하였다.
  7. relTimeobjTime 유형의 문제는 sequencing 추론 유형으로 labeling했다.
  8. 모든 답변은 소문자로 표시한다.
  9. holding a blanket과 같은 action은 relationship(holding)과 object(blanket)으로 나눌 수 있다. 하지만 action은 여러 frame과 연관된 반면 object는 하나의 frame과만 연관된다. 그래서 action이 겹치는 경우가 있다면 동일한 질문에 여러 대답이 나올 수 있다. 이를 막기 위해 frame 기반 object-relationship 표현에 우선순위를 두었다. 그러면서 actExists 템플릿은 제거되었다.
  10. 최상급 표현의 질문에서 답변은 처음 또는 마지막의 것으로 제한된다. 만약 어떤 사람이 들었던 물건들의 순서가 접시, 담요, 의자였다면 중간에 위치한 담요는 답변이 될 수 없다.

결과적으로 96.85M개의 질문-답변 쌍에서 bias를 제거하였더니 2.27M 쌍이 남았다.


3. Results

3.1. Performance across question types

HCRN이 좀 나은 성능을 기록했지만 2지선다형 문제에서 어느 모델도 50%를 넘기지 못했다. 1.0에서는 HME가 제일 잘 했었다.

3.2. Performance without visual data

어느 모델도 visual data를 썼을 때가 안 썼을 때보다 2% 이상 성능이 오르지 않았다. 이는 모델이 거의 대부분 visual feature가 아니라 언어적인 부분에 의존한다는 것을 보여준다.

3.3. Model performance by binary and open answer questions

주관식 문제에서는 모든 모델이 binary일 때보다 못했다.

3.4. Generalization to novel compositions

이전과 마찬가지로 새로운 composition에서 힘을 잘 쓰지 못한다.

3.5. Generalization to more compositional steps

1.0 때와 마찬가지로 추론 단계가 적은 것과 많은 것으로 나누어 실험하였다. open-answer question에서는 모델이 “Most-Likely”를 이겼지만 binary에서는 그렇지 못했다.

3.6. Generalization to indirect references

각 모델별로 잘하는 부분이 있고 아닌 부분이 있었다. PSAC와 HME는 binary question에서 더 높은 Precision을 기록했으며 HCRN은 open answer에서 Recall과 Precision값이 큰 차이를 보였다.

3.7. Performance by question complexity

Binary: 모델의 정답률과 추론 단계 사이에는 음의 상관관계가 있었다(0.44~0.64). Open answer: 미묘한 차이가 있다. 답변이 어떤 action인 선다형 문제(예: “그 사람은 가장 오랜 시간 동안 무엇을 하고 있었나요?”)는 구성 단계가 4개를 넘지 않으며, Most-Likely는 5.03%를 기록했다. 반면, 객관식 답변이 있는 주관식 질문의 94%는 구성 단계가 4개 이상이고 Most-Likely는 13.32%를 기록했다. 객관식(선다형) 문제에서 문제 복잡도와 정확도 사이에는 약한 양의 상관관계가 있다(0.41~0.52). visual 정보가 없을 때에도 양의 상관관계가 있다(0.42~0.59). 그러나 구성 단계, 템플릿 및 “Most-Likely” 점수 간의 연관성으로 인해 이러한 상관관계의 결과를 해석할 때는 주의가 필요하다고 밝히고 있다.


4. Discussion

  • 본 논문에서는 몇 가지 개선 사항, 특히 더 강력한 balancing algorithm이 포함된 업데이트된 버전의 AGQA를 제안한다.
  • 기존 AGQA 벤치마크의 결과와 유사하게, 실험한 모델들은 새로운 구성과 더 복잡한 문제로 일반화하는 데 어려움을 겪고 있음을 확인하였다.
  • 또한, 실험한 모델 3개 중 1개 모델만이 시각적 데이터 없이 학습된 버전보다 1% 이상 정확도가 향상되었다.
  • language-only 버전과 비교했을 때, 이 모델은 전반적으로 성능이 향상되지 않고 특정 문제 유형에서만 개선되었다.
  • 세 모델 모두 language-only 버전에 비해 개선되는 정도가 제한적이기 때문에, 추가 지표를 통해 도출할 수 있는 시각적 구성 추론에 대한 결론은 이 세 가지 모델에 대해 제한적일 수 있다.
  • 그러나 dataset 구성은 이러한 모델이 language bias에 의존하는 정도를 보여주며, 향후 모델에 대한 시각적 구성 추론에 대한 세분화된 분석을 수행할 수 있는 잠재력을 가지고 있다.
Comment  Read more