๊ฐ„๋‹จํ•œ ๋ณด๊ณ ์„œ๋ฅผ ๋กœ๋ด‡์— ์œ„์ž„ํ•˜๋Š” ๋ฐฉ๋ฒ•. Python๊ณผ Google BigQuery๋กœ ๋ด‡์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

๊ฐ„๋‹จํ•œ ๋ณด๊ณ ์„œ๋ฅผ ๋กœ๋ด‡์— ์œ„์ž„ํ•˜๋Š” ๋ฐฉ๋ฒ•. Python๊ณผ Google BigQuery๋กœ ๋ด‡์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

๋งค์ผ, ๋งค์ฃผ ๋ฐ˜๋ณต๋˜๋Š” ์ž‘์—…์ด ์žˆ์Šต๋‹ˆ๊นŒ? ์˜ˆ๋ฅผ ๋“ค์–ด ๋ณด๊ณ ์„œ ์ž‘์„ฑ. ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•˜๊ณ , ๋ถ„์„ํ•˜๊ณ , ์‹œ๊ฐํ™”(๊ทธ๋ž˜ํ”„, ์ฐจํŠธ ์ž‘์„ฑ)ํ•œ ํ›„ ์ƒ์‚ฌ์—๊ฒŒ ๋ณด๋ƒ…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด ๋ชจ๋“  ๊ฒƒ์ด ์ž๋™ํ™”๋œ๋‹ค๋ฉด ์–ด๋–จ๊นŒ์š”?

์ด ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋Š” ๋ณด๊ณ ๋ฅผ ์ž๋™ํ™”ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜๋Š” Telegram์šฉ ๋ด‡์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ฐ€์žฅ ๋ฉ‹์ง„ ์ ์€ ์ „์ฒด ํ”„๋กœ๊ทธ๋žจ์ด ๋‹จ 50์ค„์˜ ์ฝ”๋“œ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค! ์ฒ˜์Œ์œผ๋กœ Telegram์šฉ ๋ด‡์„ ์ƒ์„ฑํ•˜๋Š” ๊ฒฝ์šฐ ์ด ๋‚ด์šฉ๋„ ์ฝ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ฒŒ์‹œ.

Skillbox๋Š” ๋‹ค์Œ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ์‹ค๊ธฐ ์ฝ”์Šค ์ฒ˜์Œ๋ถ€ํ„ฐ Python ๊ฐœ๋ฐœ์ž.

์•Œ๋ฆผ: "Habr"์˜ ๋ชจ๋“  ๋…์ž๋ฅผ ์œ„ํ•œ - "Habr" ํ”„๋กœ๋ชจ์…˜ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Skillbox ๊ณผ์ •์— ๋“ฑ๋กํ•  ๋•Œ 10 ๋ฃจ๋ธ” ํ• ์ธ.

์‹œ์ž‘ํ•˜์ž

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜

์šฐ๋ฆฌ๋Š” ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋‹ค Google-ํด๋ผ์šฐ๋“œ-BigQuery Google BigQuery์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. ๋งคํŠธํ”Œ๋กฏ๋ฆฝ, numpy ะธ ํŒฌ๋” ๋ฐ์ดํ„ฐ๋ฅผ ์‹œ๊ฐํ™”ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํŒŒ์ด์ฌ ํ…”๋ ˆ๊ทธ๋žจ ๋ด‡ ์™„์„ฑ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ํ…”๋ ˆ๊ทธ๋žจ์œผ๋กœ ๋ณด๋‚ด๋“œ๋ฆฝ๋‹ˆ๋‹ค.

pip3 ์„ค์น˜ google-cloud-bigquery matplotlib numpy pandas python-telegram-bot

Google BigQuery API ์—ฐ๊ฒฐ

์„œ๋น„์Šค๋ฅผ ์ด์šฉํ•˜๋ ค๋ฉด Google BigQuery API๋ฅผ ์—ฐ๊ฒฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด ์šฐ๋ฆฌ๋Š” Google Developers Console ์ƒˆ ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ ๊ธฐ์กด ํ”„๋กœ์ ํŠธ๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

์ œ์–ดํŒ์—์„œ API ๋ฐ ์„œ๋น„์Šค ํ™œ์„ฑํ™”๋ฅผ ์„ ํƒํ•˜๊ณ  BigQuery API๋ฅผ ์ฐพ์œผ์„ธ์š”.

๊ฐ„๋‹จํ•œ ๋ณด๊ณ ์„œ๋ฅผ ๋กœ๋ด‡์— ์œ„์ž„ํ•˜๋Š” ๋ฐฉ๋ฒ•. Python๊ณผ Google BigQuery๋กœ ๋ด‡์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

ํ™œ์„ฑํ™”๋ฅผ ์„ ํƒํ•˜์—ฌ API๋ฅผ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

๊ฐ„๋‹จํ•œ ๋ณด๊ณ ์„œ๋ฅผ ๋กœ๋ด‡์— ์œ„์ž„ํ•˜๋Š” ๋ฐฉ๋ฒ•. Python๊ณผ Google BigQuery๋กœ ๋ด‡์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

๊ณ„์ • ํ‚ค ๋งŒ๋“ค๊ธฐ

๋‹ค์‹œ ๊ฐ€์ž Google Developers Console์—์„œ ์ž๊ฒฉ ์ฆ๋ช… ํƒญ, ์ž๊ฒฉ ์ฆ๋ช… ๋งŒ๋“ค๊ธฐ ๋ฐ ์„œ๋น„์Šค ๊ณ„์ • ํ‚ค๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ ๋‹ค์Œ - ์ƒˆ ์„œ๋น„์Šค ๊ณ„์ •์„ ์„ ํƒํ•˜๊ณ  ์„œ๋น„์Šค ๊ณ„์ • ์ด๋ฆ„ ํ•„๋“œ์— ์ด๋ฆ„์„ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค.

์—ญํ•  ๋“œ๋กญ๋‹ค์šด ๋ชฉ๋ก์—์„œ ํ”„๋กœ์ ํŠธ > ์†Œ์œ ์ž๋ฅผ ์„ ํƒํ•œ ๋‹ค์Œ ๋งŒ๋“ค๊ธฐ๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

๊ฐ„๋‹จํ•œ ๋ณด๊ณ ์„œ๋ฅผ ๋กœ๋ด‡์— ์œ„์ž„ํ•˜๋Š” ๋ฐฉ๋ฒ•. Python๊ณผ Google BigQuery๋กœ ๋ด‡์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

์ž๋™์œผ๋กœ ๋‹ค์šด๋กœ๋“œ๋˜๋Š” ํŒŒ์ผ์€ creds.json์ž…๋‹ˆ๋‹ค.

ํ„ฐ๋ฏธ๋„์—์„œ creds.json ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•˜์—ฌ GOOGLE_APPLICATION_CREDENTIALS๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

GOOGLE_APPLICATION_CREDENTIALS='[PATH_TO_CREDS.JSON]' ๋‚ด๋ณด๋‚ด๊ธฐ

๋ชจ๋“  ๊ฒƒ์ด ์ˆœ์กฐ๋กญ๊ฒŒ ์ง„ํ–‰๋˜์—ˆ๋‹ค๋ฉด ์ด์ œ ํ”„๋กœ๊ทธ๋žจ ์ž‘์„ฑ์„ ์‹œ์ž‘ํ•  ์ฐจ๋ก€์ž…๋‹ˆ๋‹ค.

์‘์šฉ ํ”„๋กœ๊ทธ๋žจ ๋งŒ๋“ค๊ธฐ

ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋Š” bigquery-public-data.stackoverflow์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , ๋ณด๊ณ ์„œ์—์„œ๋Š” ์ผ์ผ ๋ฐœํ–‰ ํšŸ์ˆ˜๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

๋ชจ๋“  ๊ฒƒ์ด ๋งค์šฐ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค.

ํ…Œ์ด๋ธ” ์ฟผ๋ฆฌ -> ๋ฐ์ดํ„ฐ ์‹œ๊ฐํ™” -> ์‹œ๊ฐํ™” ์ €์žฅ -> ์ด๋ฏธ์ง€ ๋ณด๋‚ด๊ธฐ

๊ฐ ์Šค๋ ˆ๋“œ๋ฅผ ์ •์˜ํ•˜๋Š” ํ•˜๋‚˜์˜ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

BigQuery์— ์ฟผ๋ฆฌ

๋จผ์ € ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

google.cloud์—์„œ BigQuery ๊ฐ€์ ธ์˜ค๊ธฐ

๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ query์ธ query_to_bigquery๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

def query_to_bigquery(query):
    client = bigquery.Client()
    query_job = client.query(query)
    result = query_job.result()
    dataframe = result.to_dataframe()
    return dataframe

์ด ํ•จ์ˆ˜๋Š” ์š”์ฒญ์„ ๋ฐ์ดํ„ฐ ํ”„๋ ˆ์ž„์œผ๋กœ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

๋ฐ์ดํ„ฐ ์‹œ๊ฐํ™”

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด matplotlib๋ฅผ ์„ ํƒํ•˜์„ธ์š”.

matplotlib.pyplot์„ plt๋กœ ๊ฐ€์ ธ ์˜ค๊ธฐ

XNUMX๊ฐœ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ x๋Š” x์ถ• ๋ฐ์ดํ„ฐ, x_label์€ ์ถ• ์ œ๋ชฉ, y๋Š” y์ถ• ๋ฐ์ดํ„ฐ, y_label์€ ์ถ• ์ œ๋ชฉ, title์€ ์ „์ฒด ์‹œ๊ฐํ™”์˜ ์ œ๋ชฉ์ž…๋‹ˆ๋‹ค.

def visualize_bar_chart(x, x_label, y, y_label, title):
    plt.title(title)
    plt.xlabel(x_label)
    plt.ylabel(y_label)
    index = np.arange(len(x))
    plt.xticks(index, x, fontsize=5, rotation=30)
    plt.bar(index, y)
    return plt

์ด๋ฏธ์ง€ ์ €์žฅ

์ด์ œ ๋‘ ๊ฐ€์ง€ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‹œ๊ฐํ™”๋ฅผ ๋งŒ๋“ค๊ณ  ์ €์žฅํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋งค์ผ ๊ฒŒ์‹œ๋œ ๊ฒŒ์‹œ๋ฌผ ์ˆ˜๋ฅผ ๋ณด๋‚ด๋“œ๋ฆฝ๋‹ˆ๋‹ค. ๋จผ์ € ์š”์ฒญ์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

query = """
        SELECT DATE(creation_date) date, COUNT(*) total_posts
        FROM `bigquery-public-data.stackoverflow.post_history`
        GROUP BY 1
        HAVING date > DATE_SUB('2018-12-02', INTERVAL 14 DAY)
        ORDER BY 1
        """

์ฟผ๋ฆฌ๋Š” 2๋…„ 2018์›” XNUMX์ผ๋ถ€ํ„ฐ XNUMX์ฃผ ๋™์•ˆ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

2018-12-02๊ฐ€ bigquery-public-data.stackoverflow.post_history์— ๊ธฐ๋ก๋œ ์ตœ์‹  ๋ฐ์ดํ„ฐ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด ๋‚ ์งœ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๊ฒฝ์šฐ์—๋Š” CURRENT_DATE()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ตœ์‹  ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

query_to_bigquery ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„ = query_to_bigquery(์ฟผ๋ฆฌ)

๊ทธ๋Ÿฐ ๋‹ค์Œ x์ถ•์— ๋‚ ์งœ ๋ฐ์ดํ„ฐ ์—ด์„ ์‚ฌ์šฉํ•˜๊ณ  y์ถ•์— total_posts ์—ด์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

x = ๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„['๋‚ ์งœ'].tolist()
y = ๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„['total_posts'].tolist()

์‹œ๊ฐํ™”_bar_chart ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‹œ๊ฐํ™”ํ•˜๊ณ  ์ด๋ฏธ์ง€๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

plt = visible_bar_chart(x=x, x_label='๋‚ ์งœ', y=y, y_label='์ด ๊ฒŒ์‹œ๋ฌผ', title='์ผ์ผ ๊ฒŒ์‹œ๋ฌผ')
plt.savefig('viz.png')

์ด ์ฝ”๋“œ๋ฅผ get_and_save_image๋ผ๋Š” ํ•จ์ˆ˜๋กœ ๋ž˜ํ•‘ํ•ฉ๋‹ˆ๋‹ค.

def get_and_save_image():
    query = """
            SELECT DATE(creation_date) date, COUNT(*) total_posts
            FROM `bigquery-public-data.stackoverflow.post_history`
            GROUP BY 1
            HAVING date > DATE_SUB('2018-12-02', INTERVAL 14 DAY)
            ORDER BY 1
            """
    dataframe = query_to_bigquery(query)  
    x = dataframe['date'].tolist()
    y = dataframe['total_posts'].tolist()
    plt = visualize_bar_chart(x=x, x_label='Date', y=y, y_label='Total Posts', title='Daily Posts')
    plt.savefig('viz.png')

์ด๋ฏธ์ง€ ๋ณด๋‚ด๊ธฐ

์ˆ˜์‹ ์ž์—๊ฒŒ ๋ณด๊ณ ์„œ๋ฅผ ๋ณด๋‚ด๋ ค๋ฉด chat_id ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ์‚ฌ์šฉ ์‚ฌ์šฉ์ž ์ •๋ณด๋ด‡ ๊ทธ๋ฆฌ๊ณ  /start๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”. ๋ด‡์€ ํ•„์š”ํ•œ ์ •๋ณด๋กœ ์‘๋‹ตํ•˜๋ฉฐ chat_id๋Š” id ํ•„๋“œ์— ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์ œ send_image ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. get_and_save_image ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฏธ์ง€๋ฅผ ๊ฒ€์ƒ‰ํ•˜๊ณ  ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ๋ชจ๋“  ๊ฒƒ์„ ์˜ฌ๋ฐ”๋ฅธ ์—ฐ๋ฝ์ฒ˜๋กœ ๋ณด๋ƒ…๋‹ˆ๋‹ค.

def send_image(bot, update):
    get_and_save_image()
    chat_id = 'CHAT_ID_RECEIVER'
    bot.send_photo(chat_id=chat_id, photo=open('viz.png','rb'))

์ฃผ์š” ํ”„๋กœ๊ทธ๋žจ

๋งˆ์ง€๋ง‰์œผ๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ํ•จ์ˆ˜์ธ main์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ๋ด‡์˜ YOUR_TOKEN์„ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์„ ์žŠ์ง€ ๋งˆ์„ธ์š”.

๊ธฐ์–ตํ•˜์„ธ์š”: ์ด ํ”„๋กœ๊ทธ๋žจ์€ ๊ท€ํ•˜๊ฐ€ ์ง€์ •ํ•œ ์‹œ๊ฐ„์— ์ž๋™์œผ๋กœ ์ด๋ฏธ์ง€๋ฅผ ๋ณด๋ƒ…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋งค์ผ ์•„์นจ XNUMX์‹œ์— ๋ณด๊ณ ์„œ๋ฅผ ๋ณด๋‚ด๋“œ๋ฆฝ๋‹ˆ๋‹ค.

def main():
    updater = Updater('YOUR_TOKEN')
    updater.job_queue.run_daily(send_image, time=datetime.datetime.strptime('9:00AM', '%I:%M%p').time(), days=(0,1,2,3,4,5,6))
    updater.start_polling()
    updater.idle()
 
if __name__ == '__main__':
    main()

๊ฒฐ๊ณผ์ ์œผ๋กœ ์šฐ๋ฆฌ์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

from google.cloud import bigquery
from telegram.ext import Updater
 
import matplotlib.pyplot as plt
import numpy as np
import datetime
 
def query_to_bigquery(query):
    client = bigquery.Client()
    query_job = client.query(query)
    result = query_job.result()
    dataframe = result.to_dataframe()
    return dataframe
 
def visualize_bar_chart(x, x_label, y, y_label, title):
    plt.title(title)
    plt.xlabel(x_label)
    plt.ylabel(y_label)
    index = np.arange(len(x))
    plt.xticks(index, x, fontsize=5, rotation=30)
    plt.bar(index, y)
    return plt
 
def get_and_save_image():
    query = """
            SELECT DATE(creation_date) date, COUNT(*) total_posts
            FROM `bigquery-public-data.stackoverflow.post_history`
            GROUP BY 1
            HAVING date > DATE_SUB('2018-12-02', INTERVAL 14 DAY)
            ORDER BY 1
            """
    dataframe = query_to_bigquery(query)  
    x = dataframe['date'].tolist()
    y = dataframe['total_posts'].tolist()
    plt = visualize_bar_chart(x=x, x_label='Date', y=y, y_label='Total Posts', title='Daily Posts')
    plt.savefig('viz.png')
 
def send_image(bot, update):
    get_and_save_image()
    chat_id = 'CHAT_ID_RECEIVER'
    bot.send_photo(chat_id=chat_id, photo=open('viz.png', 'rb'))
 
def main():
    updater = Updater('YOUR_TOKEN')
    updater.job_queue.run_daily(send_image, time=datetime.datetime.strptime('9:00AM', '%I:%M%p').time(), days=(0,1,2,3,4,5,6))
    updater.start_polling()
    updater.idle()
 
if __name__ == '__main__':
main()

ํŒŒ์ผ์„ ์ €์žฅํ•˜๊ณ  ์ด๋ฆ„์„ main.py๋กœ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

ํ„ฐ๋ฏธ๋„์— ๋‹ค์Œ ๋ช…๋ น์„ ์ž…๋ ฅํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

ํŒŒ์ด์ฌ3 ๋ฉ”์ธ.py

๋ชจ๋“  ๊ฒƒ์ด ์ค€๋น„๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ์šฐ๋ฆฌ๋Š” ์šฐ๋ฆฌ์˜ ๊ฐœ์ž… ์—†์ด ๋ณด๊ณ ์„œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” 50์ค„์˜ ์ฝ”๋“œ๋กœ ๊ตฌ์„ฑ๋œ ๋กœ๋ด‡์„ ๊ฐ–๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๋ด‡์„ ํ™•์ธํ•ด ๋ณผ๊นŒ์š”? ๋”ฐ๋ผ์„œ/send ๋ช…๋ น์„ ์„ ํƒํ•˜์—ฌ.

๊ฐ„๋‹จํ•œ ๋ณด๊ณ ์„œ๋ฅผ ๋กœ๋ด‡์— ์œ„์ž„ํ•˜๋Š” ๋ฐฉ๋ฒ•. Python๊ณผ Google BigQuery๋กœ ๋ด‡์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

์™„์„ฑ๋œ ์ฝ”๋“œ๋Š” ๋‹ค์Œ์—์„œ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด GitHub.

Skillbox๋Š” ๋‹ค์Œ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

์ถœ์ฒ˜ : habr.com

์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ถ”๊ฐ€