특징 해싱(Feature Hashing)이란? AI 범주와 단어를 고정 길이 벡터로 바꾸는 방법
TL;DR
특징 해싱(Feature Hashing)은 범주명이나 단어 같은 특징 이름을 해시 함수로 계산해 고정된 수의 벡터 칸에 넣는 전처리입니다. 학습 데이터에서 전체 어휘나 범주 사전을 만들지 않아도 같은 입력을 같은 칸으로 보낼 수 있어 큰 희소 데이터와 스트리밍 처리에 유용합니다. 다만 서로 다른 특징이 같은 칸에 들어가는 해시 충돌이 생기며, 원래 특징 이름을 정확히 되찾기 어렵기 때문에 차원 수와 품질을 함께 검증해야 합니다.
핵심 3줄 요약
- 핵심 1
출력 크기가 미리 정해집니다. 범주가 늘어나도 벡터 칸 수는 설정한 해시 차원으로 고정됩니다. - 핵심 2
별도 사전을 학습하지 않습니다. 새 범주나 단어도 같은 해시 규칙으로 바로 벡터 칸에 대응시킵니다. - 핵심 3
충돌은 오류가 아니라 절충입니다. 메모리를 줄이는 대신 다른 특징이 한 칸을 공유할 가능성을 관리합니다.
이 글에서 다룰 내용
- 특징 해싱의 한 문장 정의
- 상품 카테고리를 숫자 벡터로 바꾸는 쉬운 예시
- 큰 어휘와 새 범주를 다룰 때 중요한 이유
- 해시 함수, 칸 번호, 부호와 값 누적의 작동 순서
- 원-핫 인코딩, 해시 테이블, LSH, 임베딩과의 차이
- 텍스트 분류·추천·광고가 아닌 일반 범주형 데이터 활용
- 해시 충돌, 차원 수, 구현 일관성을 확인하는 방법
특징 해싱을 한 문장으로 정의하면 무엇인가요?
특징 해싱은 이름으로 표현된 희소 특징을 해시 함수로 계산해 정해진 차원의 숫자 벡터에 직접 대응시키는 특징 추출 방법입니다.
scikit-learn의 FeatureHasher 문서는 문자열 특징 이름에 해시 함수를 적용해 해당 이름이 들어갈 희소 행렬의 열을 계산한다고 설명합니다. 출력 열 수는 n_features로 정하며, 입력 데이터에서 범주 목록을 먼저 수집해 번호표를 만드는 단계가 없습니다.
여기서 해시는 비밀번호를 숨기는 암호화가 아닙니다. 목적은 임의 길이의 문자열을 고정 범위의 인덱스로 빠르게 대응시키는 데 있습니다. 특징 이름을 익명화하거나 원문을 안전하게 폐기하는 기능으로 이해하면 안 됩니다.
한 줄 정리: 특징 해싱은 범주 사전을 만들지 않고 특징 이름을 고정된 벡터 칸으로 바로 바꾸는 방법입니다.
쉬운 예시로 이해해 볼까요?
감자나라ai님이 고객 문의를 배송·환불·계정 같은 범주형 특징으로 바꿔 분류 모델에 넣는다고 가정해 보겠습니다. 해시 벡터의 크기를 8칸으로 정하면 각 특징 이름은 0번부터 7번 가운데 하나에 대응됩니다.
- category=배송 → 해시 계산 결과 2번 칸
- category=환불 → 해시 계산 결과 6번 칸
- channel=chat → 해시 계산 결과 2번 칸
한 문의가 배송 범주이면서 채팅 채널에서 들어왔다면 두 특징이 모두 2번 칸에 더해질 수 있습니다. 서로 다른 이름이 같은 칸을 받은 상황이 해시 충돌입니다. 모델은 2번 칸의 값은 보지만 그 값이 어느 이름에서 왔는지 완전히 구분하지 못합니다.
칸을 8개가 아니라 26만 개로 넓히면 충돌 가능성은 대체로 줄어듭니다. 대신 모델이 다루는 계수와 메모리 크기는 커집니다. 따라서 해시 차원은 무조건 작게 정하거나 크게 정할 값이 아니라 데이터 규모와 검증 결과로 고르는 설정입니다.
쉬운 예시: 특징 해싱은 모든 단어에 전용 서랍을 새로 만드는 대신, 정해진 수의 사물함에 이름을 계산해 넣는 방식과 비슷합니다. 사물함이 적으면 서로 다른 물건이 같은 칸에 들어갈 수 있습니다.
왜 AI 데이터에서 특징 해싱이 중요한가요?
큰 특징 사전을 저장하지 않아도 됩니다
원-핫 인코딩은 학습 데이터에서 본 범주마다 별도 열을 만들 수 있습니다. 사용자 ID, 검색어, 상품 코드처럼 종류가 매우 많으면 범주와 열 번호를 연결한 사전도 커집니다. 특징 해싱은 해시 함수와 출력 크기만 있으면 열 번호를 계산하므로 이 사전을 저장할 필요가 없습니다.
scikit-learn은 FeatureHasher를 DictVectorizer와 CountVectorizer보다 메모리를 적게 쓰는 대안으로 소개합니다. 특히 대규모 온라인 학습이나 메모리가 빠듯한 환경을 사용 사례로 듭니다. 희소 행렬을 사용하면 값이 있는 칸만 저장할 수도 있습니다.
처음 보는 범주도 같은 규칙으로 처리합니다
서비스에는 학습 때 없던 새 상품 코드와 새 검색어가 계속 들어옵니다. 사전 기반 인코더는 미지 범주를 무시하거나 별도 칸에 넣는 규칙이 필요합니다. 특징 해싱은 새 문자열에도 같은 함수를 적용하므로 정해진 범위 안의 칸을 곧바로 얻습니다.
출력 벡터 크기를 운영 전에 알 수 있습니다
출력 차원이 고정되면 모델 입력 스키마, 메모리 예상치와 배포 구성을 미리 맞추기 쉽습니다. TensorFlow의 Hashing 층도 num_bins로 해시 버킷 수를 정하고 문자열이나 정수를 고정 범위의 정수로 바꿉니다.
핵심 인사이트: 특징 해싱의 강점은 특징을 더 정확히 이해하는 데 있지 않습니다. 매우 많은 특징을 제한된 메모리와 고정 입력 크기로 다루는 데 있습니다.
특징 해싱은 어떻게 작동하나요?
1. 특징 이름과 값을 만듭니다
입력은 category=배송, device=mobile, word=환불처럼 이름이 있는 특징과 값의 묶음입니다. 값이 없는 단순 범주는 등장하면 1로 처리할 수 있고, 단어 빈도처럼 이미 숫자가 있으면 그 값을 사용할 수 있습니다.
이름을 만들 때 필드명과 값을 함께 쓰는 편이 안전합니다. 값이 같더라도 city=seoul과 product=seoul은 다른 의미이기 때문입니다. 필드 구분을 빼면 뜻이 다른 범주가 입력 단계부터 같은 이름이 될 수 있습니다.
2. 해시값을 벡터 칸 번호로 바꿉니다
해시 함수는 특징 이름을 큰 정수로 바꾸고, 구현은 이를 설정한 차원 범위의 인덱스로 대응시킵니다. scikit-learn FeatureHasher는 부호가 있는 32비트 MurmurHash3를 사용한다고 명시합니다. TensorFlow Hashing 층은 기본적으로 FarmHash64를 사용합니다.
3. 해당 칸에 특징값을 누적합니다
여러 특징이 같은 칸을 받으면 값이 합쳐집니다. 텍스트에서는 같은 단어가 여러 번 등장해 빈도가 누적될 수 있고, 충돌한 다른 단어의 값도 같은 칸에 더해질 수 있습니다. 그래서 출력 벡터만 보고 원래 특징 목록을 정확히 복원하기 어렵습니다.
Apache Spark의 FeatureHasher는 범주형 특징에는 one-hot 방식과 비슷하게 해시를 적용하고 숫자 특징은 열 이름의 해시로 인덱스를 정해 원래 숫자값을 둡니다. 구현별 입력 처리 규칙을 확인해야 하는 이유입니다.
4. 필요하면 부호를 번갈아 적용합니다
해시 충돌로 양수 값만 계속 더해지면 벡터의 내적과 크기에 편향이 생길 수 있습니다. 원 논문은 특징 인덱스용 해시와 더불어 양수·음수 부호를 정하는 해시를 사용한 방식을 다룹니다. scikit-learn의 alternate_sign=True도 작은 차원에서 해시 공간의 내적을 대략 보존하려는 설정입니다.
해시 충돌과 차원 수는 어떻게 봐야 하나요?
충돌은 서로 다른 특징이 한 칸을 공유하는 현상입니다
고정된 칸보다 가능한 특징 이름이 훨씬 많으면 충돌을 완전히 피할 수 없습니다. 충돌이 한두 번 있었다는 사실만으로 파이프라인이 실패한 것은 아닙니다. 중요한 것은 충돌이 실제 검증 성능과 안정성에 어느 정도 영향을 주는지입니다.
차원을 늘리면 충돌은 줄고 모델 크기는 커집니다
scikit-learn 문서는 n_features가 작으면 충돌 가능성이 커지고, 크게 잡으면 선형 모델의 계수 차원이 커진다고 안내합니다. 데이터의 고유 특징 수만 보고 한 번에 정하기보다 여러 후보 차원을 비교해야 합니다.
예를 들어 2의 14제곱, 2의 16제곱, 2의 18제곱을 후보로 두고 같은 학습·검증 분할에서 품질, 메모리, 학습 시간과 추론 시간을 함께 잽니다. 성능 차이가 거의 없다면 운영 비용이 낮은 쪽을 고를 수 있습니다.
충돌 개수만으로 품질을 단정하지 않습니다
자주 등장하는 중요한 특징끼리 충돌하는지, 드문 특징이 섞이는지에 따라 영향이 다릅니다. 전체 충돌률 하나보다 최종 업무 지표와 클래스별 오류를 함께 보는 편이 낫습니다.
실전 팁: 차원 수 후보를 바꿀 때는 같은 데이터 분할과 같은 모델 설정을 사용하세요. 그래야 품질 차이가 해시 차원에서 왔는지 비교하기 쉽습니다.
특징 해싱과 헷갈리는 용어는 무엇이 다른가요?
원-핫 인코딩과 특징 해싱의 차이
원-핫 인코딩은 보통 확인된 범주마다 뜻이 분명한 전용 열을 만듭니다. 어떤 열이 배송인지 환불인지 이름을 보존하기 쉬운 대신 범주가 많으면 열과 사전이 커집니다.
특징 해싱은 고정된 열 수를 먼저 정하고 범주를 그 안에 대응시킵니다. 처음 보는 범주도 처리하지만 충돌이 생기고 열에서 원래 이름을 역으로 찾기 어렵습니다. 설명 가능성과 메모리 가운데 무엇이 더 중요한지 보고 선택합니다.
단어 사전 벡터화와 특징 해싱의 차이
HashingVectorizer나 FeatureHasher는 사전을 학습하지 않고 단어를 해시합니다. TF-IDF처럼 전체 문서에서 문서 빈도를 배워야 하는 가중치는 별도 단계가 필요할 수 있습니다. 특징 해싱 자체가 TF-IDF를 자동 계산하는 것은 아닙니다.
일반 해시 테이블과 특징 해싱의 차이
특징 해싱은 충돌한 특징을 별도 키로 보존하지 않고 같은 벡터 좌표에서 합칠 수 있습니다. 목표가 정확한 키 조회가 아니라 제한된 차원의 모델 입력을 만드는 데 있기 때문입니다.
LSH와 특징 해싱의 차이
지역 민감 해싱(Locality-Sensitive Hashing, LSH)은 비슷한 항목이 같은 버킷에 들어갈 확률을 높여 근사 유사도 검색을 돕는 방법입니다. 가까운 벡터 후보를 빠르게 찾는 데 초점이 있습니다.
특징 해싱은 특징 이름을 모델 입력의 좌표로 바꿉니다. 비슷한 철자의 단어나 의미가 가까운 범주를 일부러 같은 칸에 보내지 않습니다. 일반 해시 결과가 같아 우연히 충돌할 뿐입니다.
임베딩과 특징 해싱의 차이
임베딩은 단어나 항목을 학습된 조밀 벡터로 표현해 관계나 의미가 가까운 항목을 비슷한 위치에 놓을 수 있습니다. 학습 가능한 임베딩 테이블이나 사전 학습 모델이 필요할 수 있습니다.
특징 해싱은 학습 없이 고정 규칙으로 희소 좌표를 정합니다. 의미 유사성을 배우지 않으며, 같은 문자열을 일관된 칸에 넣는 것이 핵심입니다.
비교 정리: 원-핫 인코딩은 이름이 있는 전용 열, 특징 해싱은 고정된 공유 열, LSH는 유사 항목 탐색, 임베딩은 학습된 의미 표현에 가깝습니다.
실전에서는 어디에 쓰이나요?
대규모 텍스트 분류
문서의 단어와 n-그램 종류가 매우 많을 때 각 항목을 해시해 고정 길이 희소 벡터로 만듭니다. 스팸 탐지, 문의 분류와 문서 분류처럼 새로운 단어가 계속 나타나는 환경에서 사전 갱신 부담을 줄일 수 있습니다.
종류가 많은 범주형 특징
상품 ID, 페이지 ID, 기기 조합이나 이벤트 이름처럼 고유값이 많은 열을 모델 입력으로 바꿀 때 씁니다. 필드명과 값을 함께 해싱하고 숫자 특징과 범주 특징이 같은 이름 공간에서 섞이지 않게 설계해야 합니다.
스트리밍과 온라인 학습
데이터 전체를 미리 훑어 사전을 만들기 어려운 흐름에서 들어오는 레코드를 즉시 변환할 수 있습니다. scikit-learn의 대규모 데이터 처리 안내도 상태 없는 특징 추출 방식으로 해싱 트릭을 소개합니다.
메모리가 제한된 모델 입력
범주 사전과 거대한 열 목록을 보관하기 어려운 서버나 기기에서 입력 차원을 통제할 수 있습니다. 다만 출력 차원이 고정돼도 행 수, 비제로 값 수와 모델 계수에 따라 실제 메모리는 달라집니다.
실전 팁: 특징 이름 해석이 꼭 필요한 업무에는 사전 기반 인코딩을 우선 검토하고, 규모와 메모리가 병목일 때 특징 해싱을 비교 후보로 두세요.
특징 해싱을 적용할 때 어떤 순서로 확인하나요?
1. 해싱할 특징과 이름 규칙을 고정합니다
범주형 열, 단어, n-그램 가운데 무엇을 해싱할지 정합니다. 대소문자, 유니코드 정규화, 공백과 구분자 처리도 기록합니다. 같은 뜻의 입력이 전처리 차이 때문에 다른 문자열이 되지 않도록 합니다.
2. 해시 구현과 차원 수 후보를 정합니다
사용할 라이브러리의 해시 함수, 부호 적용, 출력 자료형과 희소 출력 지원을 확인합니다. 운영 환경이 여러 언어라면 동일 문자열의 바이트 표현과 실제 인덱스가 같은지 샘플로 비교합니다.
3. 같은 데이터 분할로 후보를 평가합니다
여러 차원 수를 바꿔 검증 점수, 클래스별 오류, 학습 시간, 추론 시간과 메모리를 측정합니다. 원-핫이나 사전 벡터화가 가능한 규모라면 베이스라인으로 함께 비교합니다.
4. 변환 설정을 모델과 함께 버전 관리합니다
차원 수, 해시 함수, 시드나 salt, 부호 설정, 문자열 전처리를 모델 메타데이터에 남깁니다. 이 값이 달라지면 같은 입력도 다른 벡터가 되어 학습 모델이 기대한 좌표와 어긋날 수 있습니다.
5. 배포 뒤 입력 분포와 품질을 감시합니다
고유 특징 수, 비제로 값 수, 빈 입력 비율과 예측 품질을 함께 봅니다. 범주 폭증이나 데이터 형식 변경이 생기면 충돌 영향과 차원 수를 다시 평가합니다.
한 줄 정리: 특징 해싱은 fit 단계가 없더라도 설정이 없는 전처리가 아닙니다. 이름 규칙과 해시 구현, 차원 수를 모델 계약으로 고정해야 합니다.
사용할 때 무엇을 주의해야 하나요?
첫째, 해싱을 익명화로 쓰지 않습니다. 고정 범위 숫자로 바뀌었다고 개인정보나 비밀정보가 안전해지는 것은 아닙니다. 원본 데이터 보호, 접근 제어와 보존 정책은 별도로 적용해야 합니다.
둘째, 해시 충돌을 무시하지 않습니다. 차원이 너무 작으면 중요한 특징이 자주 섞여 품질이 떨어질 수 있습니다. 차원 후보를 바꿔 검증 지표와 자원 사용량을 비교하세요.
셋째, 라이브러리 교체를 단순 호환으로 보지 않습니다. scikit-learn, TensorFlow와 Spark는 해시 함수와 입력 처리 세부가 다를 수 있습니다. 프레임워크를 바꾸기 전에 알려진 문자열의 출력 좌표를 대조해야 합니다.
넷째, 원래 특징 이름을 설명해야 하는지 먼저 확인합니다. 해시 결과에는 이름 사전이 없어 계수가 큰 좌표를 보더라도 어떤 특징 때문인지 바로 해석하기 어렵습니다. 감사나 규제 보고가 중요하면 별도 추적 장치나 다른 인코딩이 필요합니다.
다섯째, 전처리 순서를 고정합니다. 대소문자 변환, 토큰화, n-그램 생성, 결측값 처리 순서가 달라지면 해시 입력도 달라집니다. 학습과 추론에서 완전히 같은 변환 코드를 사용하세요.
주의: 특징 해싱은 메모리를 줄이는 전처리이지 데이터 보안 기능이 아닙니다. 민감한 원문과 식별자는 해싱 전에 필요한 보호 조치를 따로 적용해야 합니다.
자주 묻는 질문
Q1. 특징 해싱은 학습이 필요한가요?
일반적인 특징 해싱은 범주 사전을 데이터에서 학습하지 않습니다. 정한 해시 함수와 차원 수로 바로 변환합니다. 다만 뒤에 연결한 모델은 해시 벡터와 정답으로 학습하며, 차원 수 선택도 검증이 필요합니다.
Q2. 같은 문자열은 언제나 같은 칸에 들어가나요?
같은 해시 구현, 같은 차원 수, 같은 문자열 바이트와 같은 설정이라면 일관된 칸을 얻도록 설계합니다. 라이브러리, 전처리, salt나 부호 설정이 달라지면 결과가 달라질 수 있습니다.
Q3. 해시 충돌이 하나라도 생기면 사용할 수 없나요?
아닙니다. 충돌은 고정 차원으로 압축할 때 예상되는 절충입니다. 여러 차원 수에서 최종 모델 품질을 비교해 허용할 수 있는지 판단합니다.
Q4. 특징 해싱 결과에서 원래 단어를 복원할 수 있나요?
일반적으로 정확한 역변환은 어렵습니다. 여러 특징이 같은 칸을 공유할 수 있고 해셔가 원래 이름 사전을 보관하지 않기 때문입니다. 해석이 필요하면 원본 특징 기록이나 별도 사전을 함께 관리해야 합니다.
Q5. 특징 해싱과 비밀번호 해싱은 같은 목적인가요?
아닙니다. 특징 해싱은 모델 입력의 차원을 고정하고 특징을 숫자 좌표로 바꾸는 방법입니다. 비밀번호 해싱은 비밀 검증을 위한 보안 목적이며 전용 암호학적 알고리즘과 salt 정책을 사용합니다.
출처
마무리
특징 해싱은 범주명과 단어를 해시 함수로 계산해 고정된 수의 벡터 칸에 넣는 특징 추출 방법입니다. 별도 사전을 만들지 않아 큰 희소 데이터와 새 범주를 다루기 편하지만, 다른 특징이 같은 칸에 들어가는 충돌과 낮은 해석 가능성을 받아들여야 합니다.
처음 적용한다면 세 가지를 기억하세요. 특징 이름을 만드는 규칙을 고정하고, 여러 해시 차원에서 모델 품질과 메모리를 비교하며, 해시 함수와 부호 설정을 모델과 함께 버전 관리합니다. 이 기준을 지키면 특징 해싱이 단순한 문자열 변환이 아니라 규모와 해석 가능성을 조절하는 전처리라는 점을 분명히 이해할 수 있습니다.
