TIL - Python itertools groupby 활용

CodeSignal이라는 알고리즘 문제 풀이 사이트에서 문제에서 정해준 규칙으로 문자열을 변경하는 Line Encoding이라는 문제를 푸는데..

규칙은 아래와 같았습니다.

  • First, the string is divided into the least possible number of disjoint substrings consisting of identical characters
    • for example, "aabbbc" is divided into ["aa", "bbb", "c"]
  • Next, each substring with length greater than one is replaced with a concatenation of its length and the repeating character
    • for example, substring "bbb" is replaced by "3b"
  • Finally, all the new strings are concatenated together in the same order and a new string is returned.

예시

For s = "aabbbc", the output should be
lineEncoding(s) = "2a3bc".

조금 무식하게 풀긴 풀었는데.. 풀고나서 다른 문제풀이들을 보니 itertools 모듈의 groupby를 활용해서 간단하게 푸는 것을 볼 수 있었습니다.

‘aabbbc’라는 문자열이 있을 때 아래와 같이 활용 가능합니다.

1
2
3
4
from itertools import groupby

for k, g in groupby(input_string):
print(k, list(g), len((list(g))))
1
2
3
'a' ['a', 'a'] 2
'b' ['b', 'b', 'b'] 3
'c' ['c'] 1

Growth Hacking - 인프런 그로스해킹 4

출처 - (인프런) 그로스해킹 데이터와 실험을 통해 성장하는 서비스를 만드는 방법

Growth Hacking 3 포스팅에서 다룬 내용

  • AARRR 중 Acquisition을 제외한 나머지

지표 활용

  • 지표의 속성 이해
  • 지표를 명확하게 정의
  • 선행지표 탐색
  • 지표간의 관계를 통한 인사이트 찾기

특히 실무를 하면서 지표 속성 이해와 정의 부분은 데이터 분석가만 알아야 하는 것이 아니라 지표를 활용하는 모두가 같은 이해도를 가져야 하는 것이 중요함을 느꼈습니다. 지표 정의 과정에서 지표를 활용할 사람들과 논의하여 합의를 이루고 기준이 확정된 이후 교육 등을 통해 지표로 인한 미스 커뮤니케이션 방지 노력이 필요하다고 생각합니다.

잘못된 지표 활용

  • 허무지표
    • 쉽게 변화시킬 수 있으며 실제로 중요한 숫자와 크게 상관이 없음

OMTM

  • 모든 지표를 관리하는 건 리소스 낭비
  • 지표간 우선순위가 명확하지 않으면 서비스 방향을 directing 할 수 없음
  • 즉, 성장을 위해 우리가 꼭 집중해야 하는 하나의 지표
  • Actionable하지 않은 지표가 OMTM이 되어서는 안 됨 (e.g 매출과 같은 후행지표)

강의 마지막에 A/B 테스트에 대한 내용도 있지만 이 포스팅에 같이 녹이는 것이 조금 아쉬워서 다른 자료들을 같이 참고해서 따로 포스팅하려고 합니다.

Growth Hacking - 인프런 그로스해킹 3

출처 - (인프런) 그로스해킹 데이터와 실험을 통해 성장하는 서비스를 만드는 방법

Growth Hacking 2 포스팅에서 다룬 내용

  • 지표 관리 방법
  • AARRR 중 Acquisition

Activation

  • 앞 단계인 Acquisition을 통해 데려온 사용자가 우리 서비스의 핵심 가치를 경험했는가?
  • 사용자의 서비스 경험을 단계별로 도식화 (Funnel)
    • 단계별 전환율 측정 및 분석

제가 느꼈을 때, 강의 전반적으로 계속 강조하고 있는 부분은 측정 기준을 어떻게 정했는지? 그리고 데이터를 의미있는 그룹으로 쪼개서 분석하고 있는지? 입니다. 저 또한 분석 실무를 하면서 중요하다고 느꼈던 부분입니다.

Funnel 분석

  • Cohort에 따른 차이와 그 원인을 파악하는 게 핵심
  • 마지막에 conversion한 사용자와 그렇지 않은 사용자를 가지고 앞 단계의 action data를 살펴보고 이탈 원인을 유추

Retention

  • 서비스를 경험한 사용자가 플랫폼에 남아있는가? (잔존 or 이탈)
  • Activation 과정을 통해 서비스에 대한 긍정적인 느낌을 계속 경험시켜주는 것
  • Funnel 분석과 마찬가지로 Cohort를 쪼개서 차이를 보는 게 핵심

Retention을 계산하는 여러가지 방법이 있고, 각 방법마다 장점, 단점이 있습니다. 문득 여러 회사 채용 공고에서 본 AARRR에 대한 높은 이해 문구가 떠올랐는데 이 문구가 의미하는 바가 단순히 AARRR이 이런거고 이런 지표들을 봐요~ 이게 아니라 지표가 의미하는 바를 알고 단계별로 각 서비스에 맞는 지표를 정의하고 관리하는 일련의 업무들을 잘 할 수 있는 사람일 거라고 생각합니다.

Retention 개선하기

  • 시점에 따른 접근
    • 초기에 떨어지는 속도 늦추기
    • 오랜 기간 유지시키기
  • 리텐션은 장기간 관찰해야 하는 지표
    • 어떤 action (금전적인 혜택을 주는 프로모션과 같은..) 으로 일시적인 상승은 가능할 수 있으나 장기적인 관점에서 유지하고 늘릴 수 있는 방법을 고민해야 함
  • 서비스 카테고리마다 권장되는 리텐션 수준이 다름
    • 목표 리텐션 수준 잘 정의하기

Revenue

  • 사업의 성패를 가르는 건 어떤 BM을 가지고 있으며 그게 잘 동작하는지?
  • 아무리 사용자가 서비스에 대한 평가를 잘 해줘도 이 평가가 매출에 반영되지 않으면 의미가 없음

ARPU, ARPPU, ASP 등 수익성을 보는 다양한 지표들이 있으며 마찬가지로 각 지표들의 기준을 서비스에 맞게 잘 정의하는 것이 중요합니다.

LTV (Lifetime Value)

  • 한 명의 고객이 진입부터 이탈까지 전체 활동기간 동안 누적해서 발생시키는 기대수익
  • 현실에서는 LTV 계산 공식에 맞는 인자들을 넣기 어려움
    • 차선으로 LTR (Lifetime Revenue) 사용가능
    • 계산이 어려운 Cost 말고 고객이 lifetime으로 결제한 매출의 평균 합계액 계산

Referral

  • Organic 유입의 한 단계. 기존 사용자의 추천, 입소문을 통한 사용자 확대
  • Viral Coefficient
    • User * invation rate * invitations sent per user * conversion rate / User
  • Viral Coefficient가 말해주지 않는 것
    • 초대 주기
    • Saturate 수준
      • target하는 시장에서 얼마나 saturate 되었는지에 대한 정보 없음
      • 초대 받을 수 있는 사람은 한정적
    • 전반적인 User 경험

다른 단계보다 중요도가 상대적으로 떨어지는 느낌이고 좋은 제품, 서비스가 우선!

다음 포스팅에서는 강의 마지막 내용인 지표 활용에 대한 내용을 정리하겠습니다.

Growth Hacking - 인프런 그로스해킹 2

출처 - (인프런) 그로스해킹 데이터와 실험을 통해 성장하는 서비스를 만드는 방법

Growth Hacking 1 포스팅에서 다룬 내용

  • 그로스 해킹이란?
  • PMF (Product Market Fit)

지표 관리 방법

지난 포스팅에서 다뤘던 것 처럼 그로스 해킹은 핵심 지표를 찾고, 그 지표를 성장시키는 방법을 찾는 활동입니다. 지표를 관리하는 방법은 두 가지가 있는데, 과업 기반(Task-based)와 프레임워크 기반(Framework-based)입니다. 이 부분을 읽고 지금 일하고 있는 회사에서도 주로 과업 기반의 지표를 관리하고 있었다는 것을 알게되었습니다. 되돌아보면 지금까지는 새로운 서비스 런칭이나 프로덕트의 새로운 기능이 나오면 그것과 관련된 지표만 생각하는 경향이 강했던 것 같은데 조금 더 큰 그림에서 생각해보는 노력을 해야겠습니다.

과업 기반 지표 관리

  • 부서별 담당업무를 정의하고, 해당 업무를 하면서 생기는 숫자를 지표로 관리

프레임워크 기반 지표 관리

  • 서비스 이용흐름에 따른 핵심 퍼널과 지표 정의, 지표 개선을 위한 과업 수행

효율적인 지표 관리

  • 어떤 지표가 중요한지 먼저 정의하고 이 지표를 관리하고 개선하기 위해서 어떤 task를 해야하는지 나와야 함

AARRR

  • (Acquisition) 고객 유치
  • (Activation) 활성화
  • (Retention) 리텐션
  • (Revenue) 수익화
  • (Referral) 추천

AARRR이 각각 어떤 것이고 주로 어떤 지표를 본다 <- 라는 설명은 구글링을 통해서 이미 많이 접했었습니다. 제가 더 궁금했던 내용은 실제로 AARRR 프레임워크 기반의 업무를 진행할 때, 각 단계별로 풀어야 하는 문제들은 무엇인지, 측정된 지표 자체가 가지는 의미는 무엇인지 등이었는데 다행히 강의에서 이런 궁금증을 잘 해소시켜 주었습니다.

Acquisition

사용자 구분

  • 자발적으로 우리 서비스를 찾아오는 고객 (Organic)
    • 어떻게 하면 자발적 유입을 늘릴지?
  • 마케팅 활동으로 인해 우리 서비스를 찾아온 고객 (Paid)
    • 어떻게 하면 마케팅 채널을 효율적으로 사용할지?

Acquisition 관련 기본 지표

  • 유저 획득 지표

  • 광고 집행 관련 지표

Acquisition 핵심 CAC < LTV

  • 유저 획득 비용보다 유저생애기간동안 회사에 기여하는 매출이 많아야 함
  • 회사의 생존이 걸려있는 수식
    • 어떤 지표가 Controllable한가?

UTM parameter

  • Urchin Tracking Module의 약자

  • url에 파라미터를 달아서 이사람이 어떤 경로를 통해 들어왔는지 track

  • example

    • 링크 URL + ?

      • utm_source: 어디에서 왔니?
      • utm_medium: 어떤 유형의 링크인가?
      • utm_campaign: 어떤 캠페인을 통해서 왔나?
      • utm_term: 어떤 키워드로 검색해서 왔나?
      • utm_content: 어떤 내용을 보고 왔나?

모바일 앱 어트리뷰션

어트리뷰션은 유저가 앱을 설치, 실행, 사용하는데 어떤 채널이 기여했는지 파악함으로써 모바일앱 마케팅 성과를 판단하기 위해 활용되는 개념입니다.

표준화가 되어 있지 않기 때문에 각 서비스에 맞는 어트리뷰션 기준을 세워서 활용하는 것이 중요하다고 하는데, 지금까지의 경험상 이런 전사가 합의하는 기준을 제대로 잡는 것이 생각보다 쉽지 않다는 것을 일찍이 깨달았기 때문에 집중해서 보았던 파트입니다.

어트리뷰션 윈도우

  • 어느 기간동안의 어트리뷰션을 인정할 것인가?
    • 광고 클릭하고 n일이내 설치?
  • 클릭과 뷰 어떤 행동을 어트리뷰션으로 인정할 것인가?
  • 여러 건의 어트리뷰션 터치포인트가 있는 경우, 종합적인 판단은?

이 부분에 대한 강의에서 가장 좋았던 부분은 섣부르게 어떤 하나의 기준을 전체에 적용하는 것은 위험하다는 것입니다. 기준을 위한 기준보다는 채널, 노출 크기, 지면, 알고리즘, 사용자 층 등 다양한 측면을 고려해야 한다고 말합니다.

딥링크

  • 앱 안의 특정 화면으로 이동하는 링크
  • 디퍼드 딥링크 - 딥링크의 실행을 앱 설치 이후로 지연

어트리뷰션 관련해서 고려해야 할 이슈들

  • 이 부분이 정말~~정말 좋았는데, 실제로 강사분이 업무하면서 어떤 문제들에 부딪혔고 고민했는지를 엿볼수 있었기 때문입니다. 이쪽 도메인에 대한 경험이 없는 저로서는 간접적으로나마 어떤 문제들을 해결해야 하는지 등을 보고 미리 고민해볼 수 있어서 좋았습니다.
    (이 부분에 대한 내용이 궁금하다면 인프런 그로스 해킹 강의로)

다음 포스팅에서는 Activation에 대해서 정리하겠습니다.

Growth Hacking - 인프런 그로스해킹 1

왜 그로스해킹을 공부하게 되었는지?

처음엔 그로스해킹이 무엇인지도 몰랐습니다. 업무 중에 유저 리텐션, Funnel 등 유저가 우리 서비스에 인입된 순간부터 이탈할 때까지의 여정을 데이터로 보는 경우가 종종 있었습니다. 이때마다 필요한 개념들을 각각 공부하다보니 이런 것들을 큰 틀에서 다루는 분야는 없을까 궁금했고, 그로스해킹이 그런 분야임을 알게되었습니다.

지금 제가 일하고 있는 도메인에서 그로스해킹이 밀접하게 연관이 있다고 볼 수는 없지만 대부분의 앱, 웹 기반 서비스를 제공하는 회사의 경우 이 분야의 지식들을 많이 활용하는 것을 알게 되었고 (분석가 채용 공고등을 통해) 저의 커리어를 위해서도 미리 준비해서 나쁠 것은 없겠다고 생각했습니다. (+ ad-hoc으로 보고 활용했던 개념들 정리)

그로스해킹에 관련된 지식 외에도 지표 정의 및 활용에 대한 꿀팁들도 상당히 유익했습니다. 이 부분은 데이터 분석을 처음 접하는 분 보다는 실무를 어느정도 해보신 분이 들으면 더 좋을 것 같은 내용이었습니다 !

인프런 강의명: 그로스해킹 - 데이터와 실험을 통해 성장하는 서비스를 만드는 방법

그로스 해킹이란?

  • 디자이너, 개발자, 분석가 등 데이터 기반 성장에 유관한 직군의 사람들과 핵심 지표를 중심으로 실험-학습 과정을 반복하면서 제품/서비스 성장시키는 것

PMF (Product Market Fit) - 그로스 실험의 전제 조건

  • 고객 접점없는 제품, 서비스 개발은 성공하기 어려움
  • 타겟하는 시장에서 우리 제품, 서비스를 활용하면 어떤 문제를 해결할 수 있는지?
    또한, 이 문제가 꼭 해결해야 할 가치가 있는 문제인지 확인이 필요

PMF 를 확인을 위한 지표

  • Retention
    • 시간이 지남에 따라 리텐션이 안정적으로 유지되는가?
  • Conversion
    • 주요 이벤트 전환율 (e.g 가입, 결제) 추이
  • NPS
    • 제품/서비스 적극적 추천 그룹과 비추천 그룹간 비율로 계산된 지표
    • 추천 의향을 점수로 물어보는 질문 외에 어떤 이유로 그런 점수를 줬는지 알 수 있는 설문들을 추가한다면 비추천 그룹 -> 소극적 추천 그룹 or 소극적 추천 그룹 -> 적극적 추천 그룹으로 conversion 할 수 있는 기회를 찾을 수 있지 않을까?

Python - json.loads()와 json.dumps()의 차이

JSON (JavaScript Object Notation)

json object는 key value pair로 이루어지고 { } 중괄호에 의해 둘러쌓여있습니다.

json.loads()

  • json.loads()는 문자열을 받아서 json object를 return합니다.

json.dumps()

  • json.dumps()는 json object를 받아서 문자열을 return 합니다.

json

TIL - Algorithm - adjacent element

알고리즘 지뢰찾기 문제를 풀다가 배운 것

문제 출처: codesignal arcade intro 24

처음 접근은 반복문을 통해 현재 위치에서 +1 -1 해가며 주변에 지뢰가 있는지 확인했지만, 별도로 [-1, 0, 1] list를 loop에 넣어서 인근 element를 탐색하는 방법

1
2
for x in [-1, 0, 1]:
for y in [-1, 0, 1]:

고객생애가치(Customer Lifetime Value)

고객생애가치 (Customer Lifetime Value)란 ?

고객이 과거에 회사의 제품을 구매하거나 서비스 이용료로 지불했던 금액 또는 미래 예상 지불 금액을 기반으로 고객의 가치를 정의하는 것입니다. 즉, 단기적으로만 보지 않고 장기적 관점에서 고객의 가치를 평가하는 지표입니다.

왜 중요할까?

회사 입장에서는 모든 고객에게 집중할 수 없습니다. 그렇다면 고객 중에서도 회사 이익에 기여하는 부분이 큰 고객에게 집중하는 것이 비용대비 효율이 좋을 것입니다.

또한, 가치가 낮은 고객이 있다면 어떻게 하면 충성도를 높여서 가치가 높은 고객으로 전환 시킬지에 대한 아이디어도 얻을 수 있을 것입니다.

CLV 계산방법

원문

  • 과거이력기반 (Historic)
    • 개별 고객이 거래한 과거 구매 총가치 or 총이익의 합계 측정

CLV(Historic) = (거래1 + 거래2 + 거래 3… + 거래 n) * 평균마진

  • 예측기반 (Predictive)
    • 과거이력기반보다 더 많은 데이터를 사용하기 때문에 고객 생애주기 동안 회사에 제공할 총 가치를 나타내는 데 좋은 지표가 될 수 있음
    • 가격, 할인 등의 변동을 고려할 때 정확한 예측을 결정하는 것은 어려울 수 있음

CLV(Predictive) = ((월 평균 거래횟수 * 평균구매금액) * 평균 총마진) * 평균고객수명

  • 고객수명기반 (Lifespan)

    • 고객가치와 고객 수명을 가지고 계산하는 방법
    • 평균구매가치
      • 일정 기간 동안의 총 매출을 같은 기간 동안 발생한 구매 횟수로 나누기
      • 총 매출 / 총 구매 횟수
    • 평균구매빈도
      • 위의 구매 횟수를 해당 기간 동안 구매한 고객수로 나누기
      • 총 구매 횟수 / 총 구매 고객수
    • 평균고객가치
      • 평균구매가치 * 평균구매빈도
    • 평균고객수명
      • 고객들이 계속 구매하는 년 수의 평균값 계산

    CLV(Lifespan) = 평균고객가치 * 평균고객수명

  • 동질집단기반 (Cohort)

    • 유사한 특성을 가진 고객을 수집하고 그룹화함
    • 여러 유형의 고객들 사이에서 결론을 도출하는데 유용함
    • cohort
  • 개인화기반 (Individual)

    • 개인화된 CLV는 마케팅의 더 넓은 관점을 고려하는데 유용

    • 이 CLV를 통해 어떤 마케팅 채널이 효율적인지, 누구를 타켓팅 해야하는지 등의 인사이트를 얻을 수 있음

CLV 인사이트

원문

  • 마케팅 활동을 통해 유치한 고객은 일반 고객들보다 CLV가 낮다
    • 마케팅 활동에 비용이 들어갔기 때문에 같은 질의 고객이어도 CLV가 낮음
    • 마케팅 활동을 통해 수요가 창출된 고객은 고객 이탈율이 상대적으로 높음
      • e.g) 사은품으로 유입된 고객
  • 제품 구입 빈도가 CLV에 가장 큰 영향을 끼친다
    • 제품 하나를 더 사게 하는 전략이 비싼 제품을 구입하게 하는 것보다 CLV 증가에 큰 효과가 있음
  • 같은 제품이라도 제품의 포지셔닝에 따라 CLV가 다르다
    • 고객의 의도에 맞게 마케팅을 하면 제품을 바꾸지 않고도 CLV를 바꿀 수 있음

카카오 맵 API를 활용한 좌표 <-> 주소 변환

API 활용 준비

https://developers.kakao.com

카카오 개발자 페이지에서 여러 카카오 제품의 API를 활용할 수 있는데, 그 중에서 좌표와 주소 변환 관련해서는 지도/로컬 제품을 사용하면 됩니다.

REST API 테스트 페이지에서는 어떤 기능을 어떻게 활용할 수 있는지 확인할 수 있습니다. 확인해 볼 기능은 좌표와 주소간 변환이니 아래 이미지의 노란색 2개를 확인해보겠습니다.

좌표변환

주소 -> 좌표 변환

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import requests

KAKAO_REST_API_KEY = '' # 발급받은 API KEY

def convert_address_to_coordinates(address):
"""
입력받은 주소를 WGS84 좌표계 좌표로 변환
"""

url = 'https://dapi.kakao.com/v2/local/search/address.json?query=' + address
header = {'Authorization': 'KakaoAK ' + KAKAO_REST_API_KEY}

r = requests.get(url, headers=header)

if r.status_code == 200:
lng = float(r.json()["documents"][0]["address"]['x'])
lat = float(r.json()["documents"][0]["address"]['y'])
else:
return None

return lat, lng

# Test
convert_address_to_coordinates("서울특별시 강남구 강남대로 396") # 강남역 주소

# Output
# (37.4981646510326, 127.028307900881)

좌표가 맞는지 지도에 찍어봤는데, 강남역을 가리키고 있습니다.

지도좌표검색

좌표 -> 주소 변환

이번에는 좌표에서 주소로 변환해보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def convert_coordinates_to_address(lat, lng):
"""
입력받은 위도, 경도를 도로명, 지번 주소로 변환
"""

y, x = str(lat), str(lng)
url = 'https://dapi.kakao.com/v2/local/geo/coord2address.json?x={}&y={}'.format(x, y)
header = {'Authorization': 'KakaoAK ' + KAKAO_REST_API_KEY}

r = requests.get(url, headers=header)

if r.status_code == 200:
road_address = r.json()["documents"][0]["road_address"]['address_name']
bunji_address = r.json()["documents"][0]["address"]['address_name']
else:
return None

return road_address, bunji_address

# TEST
convert_coordinates_to_address(37.4981646510326, 127.028307900881)

# Output
# ('서울특별시 강남구 강남대로 396', '서울 강남구 역삼동 804')

이전에 강남역 좌표로 얻은 것을 다시 역지오코딩을 했을 때 강남역 주소가 나오는 것을 확인할 수 있습니다.

User action 연속일수 구하기

학생 연속 출석일수 구하기

제가 학생 3명이 있는 학급을 관리하고 있는 선생님이라고 가정해보겠습니다.

출석을 열심히 한 학생에게 상을 주고 싶은데, 특정 기간동안 많이 출석한 학생보다 연속적으로 오래 출석한 학생에게 상을 주고 싶습니다.

아래 데이터는 학생 3명의 2020-12-01 ~ 2020-12-05 5일간의 출석기록입니다.
DB에 아래 데이터가 있다고 가정하고 SQL을 이용해서 학생별로 연속출석일수를 구해보겠습니다.

Table: Student

student_code date status
A 2020-12-01 1
A 2020-12-02 0
A 2020-12-03 1
A 2020-12-04 0
A 2020-12-05 1
B 2020-12-01 1
B 2020-12-02 1
B 2020-12-03 1
B 2020-12-04 0
B 2002-12-05 0
C 2020-12-01 1
C 2020-12-02 1
C 2020-12-03 0
C 2020-12-04 1
C 2020-12-05 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
with student_attendance as (
SELECT
student_code
, date
, status
, row_number() over(partition by student_code order by date) s_rownum
, row_number() over(partition by student_code, status order by date) s_t_rownum
FROM student
), student_consecutive_days as (
SELECT
student_code
, date
, status
, (rn1 - rn2) as grp
, min(date) as start_date
, max(date) as end_date
, count(*) as consecutive_days
FROM student_attendance
GROUP BY student_code, status, grp
ORDER BY student_code, start_date
)

SELECT
student_code
, max(consecutive_days) # 가장 길었던 연속일수
FROM student_consecutive_days
WHERE status = 1 # 출석했던 구간 중
GROUP BY student_code

SQL 설명

student_attendance 라는 가상 table을 만듭니다. 기존 data에서 출석여부별 연속기간을 구하기 위해 row nuber를 붙이는데
여기서 student_code를 partition으로 하는 row number와 (student_code, status) 를 partition을 하는 row number 두개가 필요합니다.

Why?

첫 번째 row number는 학생마다 날짜순서대로 붙게됩니다. 두 번째 row number는 status가 추가적으로 partiton 되어있기 때문에
학생의 날짜, 출석여부 별로 row number가 붙게됩니다. 즉, 연속적으로 출석하지 않은 시점에 row number 1과 row number 2의 차이가 발생하게 됩니다. 그러면 이 차이가 똑같은 구간은 똑같은 상태가 지속되고 있음을 나타내게 됩니다.

학생의 출석 상태별 연속되는 구간 Table을 만들고 난 후, 마지막으로 출석상태인 구간만 filtering 하여 max 연속일수를 구하면
학생별로 기간 내 가장 길었던 연속일수를 구할 수 있습니다.