AVERAGE는 열 하나의 평균을 구합니다. 그런데 “월평균 매출”, “평균 마진율”, “고객당 평균 구매액”처럼 열이 아니라 계산한 값의 평균이 필요한 순간이 곧 옵니다. 이때 쓰는 함수가 AVERAGEX입니다. 앞선 AVERAGE 함수 글에서 주문당·고객당·일평균을 이미 한 번 다뤘기 때문에, 이 글에서는 AVERAGEX가 어떻게 돌아가는지 한 가지에 집중하려 합니다. 바로 “첫 번째 인수로 무엇을 넘기느냐가 평균의 단위를 정한다”는 점입니다.
문법
AVERAGEX( <테이블>, <식> )
Microsoft 문서의 설명대로 AVERAGEX는 첫 번째 인수의 테이블을 한 줄씩 돌면서, 그 줄 기준으로 두 번째 인수의 식을 계산한 뒤, 나온 값들의 산술 평균을 돌려줍니다. 첫 번째 인수는 테이블 이름이거나 테이블을 돌려주는 식이고, 두 번째 인수는 결과가 하나의 값이 되는 식입니다. 반환값은 소수 형태의 숫자입니다. 테이블을 한 줄씩 도는 함수를 반복 함수(iterator)라고 부릅니다.
Power BI Desktop에서 측정값으로 만들기
메뉴 이름은 Power BI 버전과 언어 설정에 따라 조금 다를 수 있다는 점을 먼저 말씀드립니다. 일반적인 순서는 이렇습니다.
- 보고서 보기에서 오른쪽 필드 창의 테이블(예: Sales)을 선택합니다.
- 상단 리본에서 “새 측정값”(영문판은 New measure)을 누릅니다.
- 수식 입력줄에 이름과 식을 적고 Enter를 누릅니다.
- 만든 측정값을 표 시각화에 올리고 상품 같은 열과 함께 놓아 줄마다 값이 어떻게 달라지는지 확인합니다.
예제 데이터
설명하려고 만든 가상 데이터입니다. 결과는 Power BI에서 돌린 화면이 아니라 직접 구한 값이니, 같은 식을 본인 데이터에 적용해서 확인해 보세요.
| 월 | 상품 | 매출 | 원가 |
|---|---|---|---|
| 1월 | 노트북 | 100 | 80 |
| 1월 | 마우스 | 20 | 10 |
| 2월 | 노트북 | 150 | 120 |
| 2월 | 마우스 | 30 | 12 |
| 3월 | 노트북 | 50 | 40 |
매출 합계는 350, 원가 합계는 262입니다. 기본 측정값은 이렇게 잡아 두겠습니다.
총매출 = SUM( Sales[매출] )
총원가 = SUM( Sales[원가] )
평균의 단위는 첫 번째 인수가 정한다
같은 “평균 매출”이라도 어떤 테이블을 돌리느냐에 따라 뜻이 달라집니다.
AVERAGEX( Sales, Sales[매출] ): 행(주문 한 줄)당 평균 매출. 5행이라 350 ÷ 5 = 70AVERAGEX( VALUES( Sales[월] ), [총매출] ): 월당 평균 매출. 3개월이라 350 ÷ 3 = 약 116.7AVERAGEX( VALUES( Sales[상품] ), [총매출] ): 상품당 평균 매출. 상품별 총매출이 노트북 300, 마우스 50이라 (300 + 50) ÷ 2 = 175
세 식의 두 번째 인수는 모두 “매출”인데 결과는 70, 116.7, 175로 전혀 다릅니다. 첫 번째 인수가 “무엇 한 개당 평균인가”를 정하기 때문입니다. 보고서에 “평균 매출”이라고만 쓰면 읽는 사람이 어느 평균인지 알 수 없으니, 단위를 함께 적는 편이 좋습니다. 이 특징은 DAX Guide가 AVERAGEX의 대표 용도로 꼽는 “고객이나 날짜 같은 테이블을 돌면서 측정값을 평균 낸다”는 설명과도 이어집니다.
실무 시나리오 1: 평균 마진율 (행 평균 vs 가중 평균)
마진율은 (매출 – 원가) ÷ 매출입니다. 행마다 마진율을 구한 뒤 평균을 내면 이렇게 됩니다.
평균마진율_행평균 =
AVERAGEX(
Sales,
DIVIDE( Sales[매출] - Sales[원가], Sales[매출] )
)
| 월 | 상품 | 매출 | 원가 | 마진율 |
|---|---|---|---|---|
| 1월 | 노트북 | 100 | 80 | 20% |
| 1월 | 마우스 | 20 | 10 | 50% |
| 2월 | 노트북 | 150 | 120 | 20% |
| 2월 | 마우스 | 30 | 12 | 60% |
| 3월 | 노트북 | 50 | 40 | 20% |
다섯 행의 마진율은 20%, 50%, 20%, 60%, 20%이고 평균은 (0.2 + 0.5 + 0.2 + 0.6 + 0.2) ÷ 5 = 34%입니다. 그런데 회사 전체의 실제 마진율은 이렇게 구합니다.
마진율_전체 =
DIVIDE( [총매출] - [총원가], [총매출] )
(350 – 262) ÷ 350 = 88 ÷ 350 = 약 25.1%입니다. 34%와 25.1%는 9%포인트 가까이 차이가 납니다. 마진율이 높은 마우스는 매출 규모가 작고, 마진율이 낮은 노트북은 매출 규모가 큰데, 행 평균은 규모를 무시하고 모든 행에 같은 무게를 주기 때문입니다. 비율의 평균을 구할 때는 “행마다 같은 무게로 평균 낼 것인가, 매출 규모로 가중해서 합산할 것인가”를 먼저 정해야 합니다. 보고서에 쓰는 마진율은 대개 가중 쪽(전체 마진 ÷ 전체 매출)이 맞는 경우가 많습니다. AVERAGE 글에서 본 평균 단가의 함정과 같은 이야기입니다.
실무 시나리오 2: 월평균 매출과 상품별 월평균
“한 달 평균 얼마나 파는가”는 월 목록 위에서 총매출 측정값을 평균 내면 됩니다.
월평균매출 =
AVERAGEX(
VALUES( Sales[월] ),
[총매출]
)
VALUES가 현재 필터 상태의 월 목록(1월, 2월, 3월)을 돌려주고, AVERAGEX가 그 월을 한 달씩 돌면서 [총매출]을 계산합니다. 이때 “지금 도는 월”이 자동으로 필터로 바뀌는 컨텍스트 전환이 일어납니다. 이 개념은 CALCULATE 함수 글에 정리해 두었습니다. 월별 총매출은 1월 120, 2월 180, 3월 50이라 월평균은 350 ÷ 3 = 약 116.7입니다.
상품별 표에 올리면 이렇게 나뉩니다.
| 상품 | 월평균매출 | 계산 |
|---|---|---|
| 노트북 | 100 | (100 + 150 + 50) ÷ 3 |
| 마우스 | 25 | (20 + 30) ÷ 2 |
| 합계 | 116.7 | (120 + 180 + 50) ÷ 3 |
마우스는 3월 판매 행이 없어서, 마우스 필터 아래의 월 목록에는 1월과 2월만 들어 있습니다. 그래서 (20 + 30) ÷ 2 = 25입니다. 3월을 “매출 0″으로 보고 (20 + 30 + 0) ÷ 3 = 약 16.7로 구하고 싶다면 별도의 날짜(월) 테이블을 만들어 그 위에서 돌려야 합니다. 이때 매출이 없는 월의 총매출은 0이 아니라 빈 값이고, AVERAGEX는 빈 값을 평균에서 빼기 때문에 이 경우에도 그냥 두면 25가 나옵니다. 빈 값을 0으로 세려면 식을 [총매출] + 0처럼 바꿔야 합니다. 이 함정을 길게 다룬 글이 SQLBI의 “일평균 계산의 숨은 복잡성”이고, 관측 기간의 시작과 끝을 먼저 정하는 해법이 소개되어 있습니다. 식이 길어서 이 글에서는 다루지 않습니다.
빈 값은 빼고 0은 센다
DAX Guide의 예시가 이 규칙을 가장 간단하게 보여줍니다. 식의 결과가 1, 2, 3, 빈 값이면 평균은 2이고, 1, 2, 3, 0이면 평균은 1.5입니다. 빈 값은 평균을 낼 때 개수에서도 빠지지만 0은 한 개로 세어지기 때문입니다. Microsoft 문서도 AVERAGEX가 그 외의 규칙은 AVERAGE를 따라서 숫자가 아닌 값이나 비어 있는 값은 평균에 넣지 않는다고 설명합니다.
실무 시나리오 3: 조건에 맞는 항목만 평균 내기
“매출이 100 이상이었던 달만의 평균”처럼 일부만 평균 내려면 첫 번째 인수를 FILTER로 걸러서 넘깁니다.
큰달평균매출 =
AVERAGEX(
FILTER( VALUES( Sales[월] ), [총매출] >= 100 ),
[총매출]
)
총매출이 100 이상인 달은 1월(120)과 2월(180)이라 결과는 (120 + 180) ÷ 2 = 150입니다. 3월(50)은 평균에서 빠집니다. 한두 달의 이상값이나 극단적으로 작은 값을 빼고 보고 싶을 때 이렇게 씁니다. 다만 무엇을 이상값으로 볼지 기준은 직접 정해야 하고, 제외한 기준은 보고서에 함께 적어 두는 것이 좋습니다.
AVERAGE와 AVERAGEX, 언제 무엇을 쓸까
| 상황 | 쓸 함수 |
|---|---|
| 열 하나의 평균 | AVERAGE |
| 행마다 계산한 값(수량×단가 등)의 평균 | AVERAGEX( 테이블, 식 ) |
| 월, 고객, 상품 같은 목록 위에서 측정값의 평균 | AVERAGEX( VALUES( 열 ), [측정값] ) |
| 일부만 걸러서 평균 | AVERAGEX( FILTER( … ), 식 ) 또는 CALCULATE와 AVERAGE |
| 비율(마진율 등)의 평균 | 가중 방식( 합계 ÷ 합계 )을 먼저 검토 |
DAX Guide에 따르면 열 하나에 쓴 AVERAGE는 내부적으로 AVERAGEX를 실행하는 것과 같고 성능 차이가 없습니다. 그러니 열 하나의 평균이라면 읽기 쉬운 AVERAGE를, 식이 필요하면 AVERAGEX를 쓰면 됩니다. 다만 AVERAGEX는 행을 하나씩 도는 함수라서, 반복 안에 무거운 계산이 들어가면 그만큼 느려질 수 있습니다.
알아둘 점
- DirectQuery 모드에서는 계산 열이나 행 수준 보안 규칙 안에서 AVERAGEX를 쓸 수 없다고 Microsoft 문서에 적혀 있습니다. DAX Guide는 측정값과 계산 열에서 지원된다고 안내해 설명이 다르니, 쓰는 환경에서 직접 확인해 보세요.
- 식 안에서 여러 연산을 쓸 때는 괄호로 계산 순서를 분명히 해야 한다고 Microsoft 문서가 안내합니다.
- 두 번째 인수의 식은 한 줄마다 하나의 값이 나오는 식이어야 합니다.
- 지역 설정에 따라 인수 구분자가 쉼표 대신 세미콜론일 수 있습니다. 식을 붙여 넣었는데 오류가 난다면 먼저 확인해 보세요.
자주 하는 실수
- 평균의 단위를 정하지 않고 “평균 매출”이라고 표기: 행당인지, 월당인지, 상품당인지 밝히세요.
- 비율을 행마다 구해 평균: 규모가 다른 행이 섞이면 실제 비율과 크게 달라집니다.
- 매출이 없는 달이 0으로 평균에 들어갔다고 착각: 빈 값은 빠집니다.
- AVERAGE( Sales[매출] * Sales[단가] )처럼 식을 AVERAGE에 바로 넣음: AVERAGE는 열만 받으니 AVERAGEX가 필요합니다.
비슷한 함수
- AVERAGE: 열 하나의 평균
- SUMX, MINX, MAXX, COUNTX: 같은 방식으로 행마다 계산한 뒤 합계, 최소, 최대, 개수를 구하는 반복 함수
- MEDIAN: 평균 대신 중앙값이 필요할 때
정리
AVERAGEX는 “첫 번째 인수의 테이블을 한 줄씩 돌며 두 번째 인수의 식을 평균 낸다”는 한 문장으로 요약됩니다. 어떤 테이블을 돌리느냐가 평균의 단위를 정하고, 빈 값은 빠지고 0은 세어진다는 규칙, 그리고 비율의 평균은 가중 방식을 먼저 검토해야 한다는 점만 기억해 두세요. 예제는 가상 데이터이니 본인 모델의 열 이름으로 바꿔 직접 확인해 보시고, 동작은 버전에 따라 다를 수 있어 공식 문서도 함께 보시길 권합니다.
참고한 자료
- Microsoft Learn, AVERAGEX function (DAX): https://learn.microsoft.com/en-us/dax/averagex-function-dax
- Microsoft Learn, AVERAGE function (DAX): https://learn.microsoft.com/en-us/dax/average-function-dax
- DAX Guide, AVERAGEX: https://dax.guide/averagex/
- SQLBI, The hidden complexity of a daily average in DAX: https://www.sqlbi.com/articles/the-hidden-complexity-of-a-daily-average-in-dax/
- SQLBI, Context transition in DAX explained visually: https://www.sqlbi.com/articles/context-transition-in-dax-explained-visually/