Gorio Tech Blog search

Adapting-large-language-models-to-domains-via-reading-comprehension 요약 설명

|

이번 글에서는 AdaptLLM: Adapting-large-language-models-to-domains-via-reading-comprehension 논문의 핵심 포인트만 간단히 정리한다.

  • 2023년 7월(Arxiv), ICLR 2024
  • Daixuan Cheng, Shaohan Huang B & Furu Wei.
  • Microsoft Research,Beijing Institute for General Artificial Intelligence (BIGAI)
  • 논문 링크
  • Github
  • Huggingface

요약

  • Domain-specific corpora에서 pre-training 하는 것은 모델이 해당 domain에 대한 지식을 학습할 수 있도록 해 주지만, 반대로 해당 domain 외 일반적 task, 또는 prompting 능력을 저하시킬 수 있다.
  • 이 논문에서는
    • 해당 사실을 발견하여, 이를 해결할 수 있는 방법으로
    • raw corpora를 reading comprehension text로 변환시켜 해당 데이터로 학습하는 과정을 통해 prompting 성능을 떨어뜨리지 않으면서도 domain-specific 지식을 학습하는 방법을 제안한다.
  • 결과적으로
    • biomedicine, finance, law 3가지 분야에서 보다 큰 모델과 비슷한 수준의 성능을 확보하였고 (특히, finance에서는 BloombergGPT와 비슷한 수준의 성능을 보였다)
    • 그러면서도 일반적 성능이 떨어지지 않음을 실험을 통해 보였다.
  • 논문의 핵심 내용은 위의 요약과 같다.
  • 남은 중요한 부분은 raw corpora를 reading comprehension text로 변환시키는 방법에 대한 부분인데,
    • 아래 figure 02처럼 $-$ 그냥 평범한 글을, 특정한 regex expression에 맞는 부분이 있으면 그것을 일종의 QA task처럼 바꾸는 과정이다.
    • 이렇게 생성된 task들을 해당 domain에 맞는 데이터로 학습시키면 해당 domain에 대한 지식을 학습할 수 있게 된다.
    • 생성한 task는 보통의 QA task와 비슷하므로, 그냥 raw corpora를 학습시키는 것에 비해 모델이 원래 가지고 있던 instruction-following 능력을 저하시키지 않는다.
    • 발굴한 task들은 요약, 특정 주제에 대한 문장 생성, 추론, 문단 완성 등이 있다.
  • 전체 pattern은 아래 table 02와 같다.
  • 코멘트. 간단한 방식으로 raw corpora를 reading comprehension task로 변환시키는 방법이 매우 흥미롭다.
Comment  Read more

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