피처 추출 및 변환 - RDD 기반 API

피처 추출 및 변환 - RDD 기반 API (Feature Extraction and Transformation – RDD-based API)

머신러닝에서 피처(feature)를 어떻게 표현하느냐는 모델 성능에 큰 영향을 줘요. 이 페이지에서는 텍스트를 벡터로 바꾸는 TF-IDF와 Word2Vec, 그리고 피처를 표준화하거나 정규화하는 StandardScaler/Normalizer, 피처를 선택하는 ChiSqSelector 등 RDD 기반 API의 피처 추출·변환 기법을 예제와 함께 소개해 드릴게요.

출처: 문서

본문

목차 (Table of Contents)

TF-IDF

참고 DataFrame 기반 API를 사용하는 것이 좋아요. 자세한 내용은 TF-IDF에 대한 ML 사용자 가이드를 참고하세요.

용어 빈도-역문서 빈도 (TF-IDF)는 텍스트 마이닝에서 문헌집(corpus) 안의 문서에서 어떤 용어가 얼마나 중요한지를 반영하기 위해 널리 쓰이는 피처 벡터화 방법이에요. 용어를 $t$, 문서를 $d$, 문헌집을 $D$라고 표기해요. 용어 빈도 $TF(t, d)$는 용어 $t$가 문서 $d$에 나타난 횟수이고, 문서 빈도 $DF(t, D)$는 용어 $t$를 포함하는 문서의 수입니다. 용어 빈도만으로 중요도를 측정하면, 아주 자주 나타나지만 문서에 대한 정보를 거의 담지 못하는 용어(예: "a", "the", "of")를 지나치게 강조하기 쉽습니다. 용어가 문헌집 전체에 아주 자주 나타난다면, 그 용어는 특정 문서에 대한 특별한 정보를 담지 않는다는 뜻이에요.

역문서 빈도는 용어가 제공하는 정보량을 측정하는 수치입니다:

\[ IDF(t, D) = \log \frac{|D| + 1}{DF(t, D) + 1}, \]

여기서 $|D|$는 문헌집의 총 문서 수입니다. 로그를 사용하므로, 용어가 모든 문서에 나타나면 IDF 값이 0이 돼요. 문헌집 밖의 용어에서 0으로 나누는 것을 피하기 위해 평활(smoothing) 항이 적용된다는 점을 참고하세요. TF-IDF 측정값은 단순히 TF와 IDF의 곱이에요:

\[ TFIDF(t, d, D) = TF(t, d) \cdot IDF(t, D). \]

용어 빈도와 문서 빈도의 정의에는 여러 변형이 있어요. spark.mllib에서는 유연하게 만들기 위해 TF와 IDF를 분리해요.

우리의 용어 빈도 구현은 해싱 트릭(hashing trick)을 활용합니다. 원시 피처를 해시 함수를 적용해 인덱스(용어)로 매핑해요. 그런 다음 매핑된 인덱스를 기반으로 용어 빈도를 계산합니다. 이 접근 방식은 대규모 문헌집에서 비쌀 수 있는 전역 용어-인덱스 맵을 계산할 필요를 피하지만, 해시 후 서로 다른 원시 피처가 같은 용어가 될 수 있는 해시 충돌 가능성이 있어요. 충돌 확률을 줄이기 위해 대상 피처 차원, 즉 해시 테이블의 버킷 수를 늘릴 수 있습니다. 기본 피처 차원은 $2^{20} = 1,048,576$이에요.

참고: spark.mllib는 텍스트 분할(segmentation) 도구를 제공하지 않아요. 사용자는 Stanford NLP Groupscalanlp/chalk을 참고하세요.

Python:

TF와 IDF는 [HashingTF](api/python/reference/api/pyspark.mllib.feature.HashingTF.html)와 [IDF](api/python/reference/api/pyspark.mllib.feature.IDF.html)에 구현되어 있어요. `HashingTF`는 리스트의 RDD를 입력으로 받습니다. 각 레코드는 문자열이나 다른 타입의 이터러블일 수 있어요.

API에 대한 자세한 내용은 [`HashingTF` Python 문서](api/python/reference/api/pyspark.mllib.feature.HashingTF.html)를 참고하세요.
from pyspark.mllib.feature import HashingTF, IDF

# Load documents (one per line).
documents = sc.textFile("data/mllib/kmeans_data.txt").map(lambda line: line.split(" "))

hashingTF = HashingTF()
tf = hashingTF.transform(documents)

# While applying HashingTF only needs a single pass to the data, applying IDF needs two passes:
# First to compute the IDF vector and second to scale the term frequencies by IDF.
tf.cache()
idf = IDF().fit(tf)
tfidf = idf.transform(tf)

# spark.mllib's IDF implementation provides an option for ignoring terms
# which occur in less than a minimum number of documents.
# In such cases, the IDF for these terms is set to 0.
# This feature can be used by passing the minDocFreq value to the IDF constructor.
idfIgnore = IDF(minDocFreq=2).fit(tf)
tfidfIgnore = idfIgnore.transform(tf)
전체 예제 코드는 Spark 저장소의 "examples/src/main/python/mllib/tf_idf_example.py"에서 확인할 수 있어요.

Scala:

TF와 IDF는 [HashingTF](api/scala/org/apache/spark/mllib/feature/HashingTF.html)와 [IDF](api/scala/org/apache/spark/mllib/feature/IDF.html)에 구현되어 있어요. `HashingTF`는 `RDD[Iterable[_]]`를 입력으로 받습니다. 각 레코드는 문자열이나 다른 타입의 이터러블일 수 있어요.

API에 대한 자세한 내용은 [`HashingTF` Scala 문서](api/scala/org/apache/spark/mllib/feature/HashingTF.html)를 참고하세요.
import org.apache.spark.mllib.feature.{HashingTF, IDF}
import org.apache.spark.mllib.linalg.Vector
import org.apache.spark.rdd.RDD

// Load documents (one per line).
val documents: RDD[Seq[String]] = sc.textFile("data/mllib/kmeans_data.txt")
  .map(_.split(" ").toSeq)

val hashingTF = new HashingTF()
val tf: RDD[Vector] = hashingTF.transform(documents)

// While applying HashingTF only needs a single pass to the data, applying IDF needs two passes:
// First to compute the IDF vector and second to scale the term frequencies by IDF.
tf.cache()
val idf = new IDF().fit(tf)
val tfidf: RDD[Vector] = idf.transform(tf)

// spark.mllib IDF implementation provides an option for ignoring terms which occur in less than
// a minimum number of documents. In such cases, the IDF for these terms is set to 0.
// This feature can be used by passing the minDocFreq value to the IDF constructor.
val idfIgnore = new IDF(minDocFreq = 2).fit(tf)
val tfidfIgnore: RDD[Vector] = idfIgnore.transform(tf)
전체 예제 코드는 Spark 저장소의 "examples/src/main/scala/org/apache/spark/examples/mllib/TFIDFExample.scala"에서 확인할 수 있어요.

Word2Vec

Word2Vec은 단어의 분산 벡터 표현을 계산해요. 분산 표현의 주요 장점은 비슷한 단어가 벡터 공간에서 가깝다는 것인데, 이는 새로운 패턴으로의 일반화를 더 쉽게 하고 모델 추정을 더 견고하게 만들어요. 분산 벡터 표현은 개체명 인식(name entity recognition), 중의성 해소(disambiguation), 파싱, 품사 태깅, 기계 번역 등 많은 자연어 처리 애플리케이션에서 유용한 것으로 알려져 있어요.

모델 (Model)

우리의 Word2Vec 구현에서는 skip-gram 모델을 사용해요. skip-gram의 훈련 목적은 같은 문장 안에서 단어의 맥락을 잘 예측하는 단어 벡터 표현을 학습하는 것입니다. 수학적으로, 훈련 단어 시퀀스 $w_1, w_2, \dots, w_T$가 주어지면 skip-gram 모델의 목적은 평균 로그 우도를 최대화하는 것이에요:

\[ \frac{1}{T} \sum_{t = 1}^{T}\sum_{j=-k}^{j=k} \log p(w_{t+j} | w_t) \]

여기서 $k$는 훈련 윈도우 크기입니다.

skip-gram 모델에서 모든 단어 $w$는 두 벡터 $u_w$$v_w$와 연관되는데, 이들은 각각 단어로서의 $w$와 맥락으로서의 $w$의 벡터 표현이에요. 단어 $w_j$가 주어졌을 때 단어 $w_i$를 올바르게 예측할 확률은 softmax 모델로 결정되는데, 다음과 같아요:

\[ p(w_i | w_j ) = \frac{\exp(u_{w_i}^{\top}v_{w_j})}{\sum_{l=1}^{V} \exp(u_l^{\top}v_{w_j})} \]

여기서 $V$는 어휘 크기입니다.

softmax를 가진 skip-gram 모델은 $\log p(w_i | w_j)$를 계산하는 비용이 $V$에 비례하는데 $V$가 수백만 단위가 될 수 있어서 비싸요. Word2Vec 훈련을 가속화하기 위해 계층적 softmax(hierarchical softmax)를 사용했는데, 이는 $\log p(w_i | w_j)$ 계산의 복잡도를 $O(\log(V))$로 줄여줍니다.

예제 (Example)

아래 예제는 텍스트 파일을 로드해 Seq[String]의 RDD로 파싱하고, Word2Vec 인스턴스를 만들고 입력 데이터로 Word2VecModel을 피팅하는 방법을 보여줘요. 마지막으로 지정된 단어의 상위 40개 유의어를 표시합니다. 예제를 실행하려면 먼저 text8 데이터를 다운로드해 선호하는 디렉터리에 압축을 푸세요. 여기서는 추출된 파일이 text8이고 spark 셸을 실행하는 디렉터리와 같은 곳에 있다고 가정해요.

Python:

API에 대한 자세한 내용은 [`Word2Vec` Python 문서](api/python/reference/api/pyspark.mllib.feature.Word2Vec.html)를 참고하세요.
from pyspark.mllib.feature import Word2Vec

inp = sc.textFile("data/mllib/sample_lda_data.txt").map(lambda row: row.split(" "))

word2vec = Word2Vec()
model = word2vec.fit(inp)

synonyms = model.findSynonyms('1', 5)

for word, cosine_distance in synonyms:
    print("{}: {}".format(word, cosine_distance))
전체 예제 코드는 Spark 저장소의 "examples/src/main/python/mllib/word2vec_example.py"에서 확인할 수 있어요.

Scala:

API에 대한 자세한 내용은 [`Word2Vec` Scala 문서](api/scala/org/apache/spark/mllib/feature/Word2Vec.html)를 참고하세요.
import org.apache.spark.mllib.feature.{Word2Vec, Word2VecModel}

val input = sc.textFile("data/mllib/sample_lda_data.txt").map(line => line.split(" ").toSeq)

val word2vec = new Word2Vec()

val model = word2vec.fit(input)

val synonyms = model.findSynonyms("1", 5)

for ((synonym, cosineSimilarity) <- synonyms) {
  println(s"$synonym $cosineSimilarity")
}

// Save and load model
model.save(sc, "myModelPath")
val sameModel = Word2VecModel.load(sc, "myModelPath")
전체 예제 코드는 Spark 저장소의 "examples/src/main/scala/org/apache/spark/examples/mllib/Word2VecExample.scala"에서 확인할 수 있어요.

StandardScaler

훈련 세트의 샘플에 대한 열 요약 통계를 사용해 피처를 단위 분산으로 스케일링하거나/그리고 평균을 제거해 표준화합니다. 이것은 아주 흔한 전처리 단계예요.

예를 들어 Support Vector Machines의 RBF 커널이나 L1, L2 정규화 선형 모델은 모든 피처가 단위 분산 및/또는 0 평균을 가질 때 일반적으로 더 잘 동작해요.

표준화는 최적화 과정 중 수렴 속도를 개선할 수 있고, 분산이 매우 큰 피처가 모델 훈련 중 지나치게 큰 영향을 미치는 것을 막아줍니다.

모델 피팅 (Model Fitting)

StandardScaler는 생성자에 다음 파라미터가 있어요:

  • withMean 기본값 False. 스케일링 전에 평균으로 데이터를 중심화합니다. 조밀(dense) 출력을 만들므로 희소 입력에 적용할 때 주의하세요.
  • withStd 기본값 True. 데이터를 단위 표준 편차로 스케일링합니다.

StandardScaler에는 RDD[Vector] 입력을 받아 요약 통계를 학습한 다음, StandardScaler를 어떻게 구성했느냐에 따라 입력 데이터셋을 단위 표준 편차 및/또는 0 평균 피처로 변환할 수 있는 모델을 반환하는 fit 메서드를 제공해요.

이 모델은 VectorTransformer를 구현하는데, 이는 Vector에 표준화를 적용해 변환된 Vector를 만들거나 RDD[Vector]에 적용해 변환된 RDD[Vector]를 만들 수 있어요.

피처의 분산이 0이면 그 피처에 대해 Vector에서 기본값 0.0을 반환한다는 점을 참고하세요.

예제 (Example)

아래 예제는 libsvm 형식의 데이터셋을 로드하고, 새 피처가 단위 표준 편차 및/또는 0 평균을 갖도록 피처를 표준화하는 방법을 보여줘요.

Python:

API에 대한 자세한 내용은 [`StandardScaler` Python 문서](api/python/reference/api/pyspark.mllib.feature.StandardScaler.html)를 참고하세요.
from pyspark.mllib.feature import StandardScaler
from pyspark.mllib.linalg import Vectors
from pyspark.mllib.util import MLUtils

data = MLUtils.loadLibSVMFile(sc, "data/mllib/sample_libsvm_data.txt")
label = data.map(lambda x: x.label)
features = data.map(lambda x: x.features)

scaler1 = StandardScaler().fit(features)
scaler2 = StandardScaler(withMean=True, withStd=True).fit(features)

# data1 will be unit variance.
data1 = label.zip(scaler1.transform(features))

# data2 will be unit variance and zero mean.
data2 = label.zip(scaler2.transform(features.map(lambda x: Vectors.dense(x.toArray()))))
전체 예제 코드는 Spark 저장소의 "examples/src/main/python/mllib/standard_scaler_example.py"에서 확인할 수 있어요.

Scala:

API에 대한 자세한 내용은 [`StandardScaler` Scala 문서](api/scala/org/apache/spark/mllib/feature/StandardScaler.html)를 참고하세요.
import org.apache.spark.mllib.feature.{StandardScaler, StandardScalerModel}
import org.apache.spark.mllib.linalg.Vectors
import org.apache.spark.mllib.util.MLUtils

val data = MLUtils.loadLibSVMFile(sc, "data/mllib/sample_libsvm_data.txt")

val scaler1 = new StandardScaler().fit(data.map(x => x.features))
val scaler2 = new StandardScaler(withMean = true, withStd = true).fit(data.map(x => x.features))
// scaler3 is an identical model to scaler2, and will produce identical transformations
val scaler3 = new StandardScalerModel(scaler2.std, scaler2.mean)

// data1 will be unit variance.
val data1 = data.map(x => (x.label, scaler1.transform(x.features)))

// data2 will be unit variance and zero mean.
val data2 = data.map(x => (x.label, scaler2.transform(Vectors.dense(x.features.toArray))))
전체 예제 코드는 Spark 저장소의 "examples/src/main/scala/org/apache/spark/examples/mllib/StandardScalerExample.scala"에서 확인할 수 있어요.

Normalizer

Normalizer는 개별 샘플을 단위 $L^p$ 노름으로 스케일링해요. 이것은 텍스트 분류나 클러스터링에서 흔한 연산입니다. 예를 들어 두 개의 $L^2$ 정규화된 TF-IDF 벡터의 내적(dot product)은 그 벡터들의 코사인 유사도가 돼요.

Normalizer는 생성자에 다음 파라미터가 있어요:

  • p $L^p$ 공간에서의 정규화, 기본값 $p = 2$.

NormalizerVectorTransformer를 구현해 Vector에 정규화를 적용해 변환된 Vector를 만들거나 RDD[Vector]에 적용해 변환된 RDD[Vector]를 만들 수 있어요.

입력의 노름이 0이면 입력 벡터를 반환한다는 점을 참고하세요.

예제 (Example)

아래 예제는 libsvm 형식의 데이터셋을 로드하고, $L^2$ 노름과 $L^\infty$ 노름으로 피처를 정규화하는 방법을 보여줘요.

Python:

API에 대한 자세한 내용은 [`Normalizer` Python 문서](api/python/reference/api/pyspark.mllib.feature.Normalizer.html)를 참고하세요.
from pyspark.mllib.feature import Normalizer
from pyspark.mllib.util import MLUtils

data = MLUtils.loadLibSVMFile(sc, "data/mllib/sample_libsvm_data.txt")
labels = data.map(lambda x: x.label)
features = data.map(lambda x: x.features)

normalizer1 = Normalizer()
normalizer2 = Normalizer(p=float("inf"))

# Each sample in data1 will be normalized using $L^2$ norm.
data1 = labels.zip(normalizer1.transform(features))

# Each sample in data2 will be normalized using $L^\infty$ norm.
data2 = labels.zip(normalizer2.transform(features))
전체 예제 코드는 Spark 저장소의 "examples/src/main/python/mllib/normalizer_example.py"에서 확인할 수 있어요.

Scala:

API에 대한 자세한 내용은 [`Normalizer` Scala 문서](api/scala/org/apache/spark/mllib/feature/Normalizer.html)를 참고하세요.
import org.apache.spark.mllib.feature.Normalizer
import org.apache.spark.mllib.util.MLUtils

val data = MLUtils.loadLibSVMFile(sc, "data/mllib/sample_libsvm_data.txt")

val normalizer1 = new Normalizer()
val normalizer2 = new Normalizer(p = Double.PositiveInfinity)

// Each sample in data1 will be normalized using $L^2$ norm.
val data1 = data.map(x => (x.label, normalizer1.transform(x.features)))

// Each sample in data2 will be normalized using $L^\infty$ norm.
val data2 = data.map(x => (x.label, normalizer2.transform(x.features)))
전체 예제 코드는 Spark 저장소의 "examples/src/main/scala/org/apache/spark/examples/mllib/NormalizerExample.scala"에서 확인할 수 있어요.

ChiSqSelector

피처 선택 (Feature selection)은 모델 구축에 사용할 관련 피처를 식별하려고 시도해요. 이것은 피처 공간의 크기를 줄여 속도와 통계적 학습 동작을 모두 개선할 수 있어요.

ChiSqSelector는 카이-제곱(Chi-Squared) 피처 선택을 구현합니다. 범주형 피처를 가진 레이블된 데이터에서 동작해요. ChiSqSelector는 어떤 피처를 고를지 결정하기 위해 카이-제곱 독립성 검정을 사용합니다. 다섯 가지 선택 방법을 지원해요: numTopFeatures, percentile, fpr, fdr, fwe:

  • numTopFeatures는 카이-제곱 검정에 따라 고정된 수의 상위 피처를 선택합니다. 이는 가장 예측력이 높은 피처를 산출하는 것과 비슷해요.
  • percentilenumTopFeatures와 비슷하지만 고정된 수 대신 전체 피처의 일정 비율을 선택해요.
  • fpr는 p-값이 임계값 아래인 모든 피처를 선택하므로 선택의 오탐율(false positive rate)을 제어해요.
  • fdrBenjamini-Hochberg 절차를 사용해 오발견율(false discovery rate)이 임계값 아래인 모든 피처를 선택해요.
  • fwe는 p-값이 임계값 아래인 모든 피처를 선택합니다. 임계값은 1/numFeatures로 스케일링되므로 선택의 가족별 오류율(family-wise error rate)을 제어해요.

기본적으로 선택 방법은 numTopFeatures이고, 기본 상위 피처 수는 50으로 설정되어 있어요. 사용자는 setSelectorType을 사용해 선택 방법을 고를 수 있습니다.

선택할 피처 수는 유보된 검증 세트(held-out validation set)를 사용해 튜닝할 수 있어요.

모델 피팅 (Model Fitting)

fit 메서드는 범주형 피처를 가진 RDD[LabeledPoint] 입력을 받아 요약 통계를 학습한 다음, 입력 데이터셋을 축소된 피처 공간으로 변환할 수 있는 ChiSqSelectorModel을 반환해요. ChiSqSelectorModelVector에 적용해 축소된 Vector를 만들거나 RDD[Vector]에 적용해 축소된 RDD[Vector]를 만들 수 있습니다.

선택된 피처 인덱스 배열(오름차순으로 정렬되어야 함)을 제공해 ChiSqSelectorModel을 직접 구성할 수도 있다는 점을 참고하세요.

예제 (Example)

다음 예제는 ChiSqSelector의 기본 사용법을 보여줘요. 사용된 데이터셋은 각 피처에 대해 0에서 255까지 변하는 그레이스케일 값으로 이루어진 피처 행렬을 가져요.

Scala:

API에 대한 자세한 내용은 [`ChiSqSelector` Scala 문서](api/scala/org/apache/spark/mllib/feature/ChiSqSelector.html)를 참고하세요.
import org.apache.spark.mllib.feature.ChiSqSelector
import org.apache.spark.mllib.linalg.Vectors
import org.apache.spark.mllib.regression.LabeledPoint
import org.apache.spark.mllib.util.MLUtils

// Load some data in libsvm format
val data = MLUtils.loadLibSVMFile(sc, "data/mllib/sample_libsvm_data.txt")
// Discretize data in 16 equal bins since ChiSqSelector requires categorical features
// Even though features are doubles, the ChiSqSelector treats each unique value as a category
val discretizedData = data.map { lp =>
  LabeledPoint(lp.label, Vectors.dense(lp.features.toArray.map { x => (x / 16).floor }))
}
// Create ChiSqSelector that will select top 50 of 692 features
val selector = new ChiSqSelector(50)
// Create ChiSqSelector model (selecting features)
val transformer = selector.fit(discretizedData)
// Filter the top 50 features from each feature vector
val filteredData = discretizedData.map { lp =>
  LabeledPoint(lp.label, transformer.transform(lp.features))
}
전체 예제 코드는 Spark 저장소의 "examples/src/main/scala/org/apache/spark/examples/mllib/ChiSqSelectorExample.scala"에서 확인할 수 있어요.

Java:

API에 대한 자세한 내용은 [`ChiSqSelector` Java 문서](api/java/org/apache/spark/mllib/feature/ChiSqSelector.html)를 참고하세요.
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.mllib.feature.ChiSqSelector;
import org.apache.spark.mllib.feature.ChiSqSelectorModel;
import org.apache.spark.mllib.linalg.Vectors;
import org.apache.spark.mllib.regression.LabeledPoint;
import org.apache.spark.mllib.util.MLUtils;

JavaRDD<LabeledPoint> points = MLUtils.loadLibSVMFile(jsc.sc(),
  "data/mllib/sample_libsvm_data.txt").toJavaRDD().cache();

// Discretize data in 16 equal bins since ChiSqSelector requires categorical features
// Although features are doubles, the ChiSqSelector treats each unique value as a category
JavaRDD<LabeledPoint> discretizedData = points.map(lp -> {
  double[] discretizedFeatures = new double[lp.features().size()];
  for (int i = 0; i < lp.features().size(); ++i) {
    discretizedFeatures[i] = Math.floor(lp.features().apply(i) / 16);
  }
  return new LabeledPoint(lp.label(), Vectors.dense(discretizedFeatures));
});

// Create ChiSqSelector that will select top 50 of 692 features
ChiSqSelector selector = new ChiSqSelector(50);
// Create ChiSqSelector model (selecting features)
ChiSqSelectorModel transformer = selector.fit(discretizedData.rdd());
// Filter the top 50 features from each feature vector
JavaRDD<LabeledPoint> filteredData = discretizedData.map(lp ->
  new LabeledPoint(lp.label(), transformer.transform(lp.features())));
전체 예제 코드는 Spark 저장소의 "examples/src/main/java/org/apache/spark/examples/mllib/JavaChiSqSelectorExample.java"에서 확인할 수 있어요.

ElementwiseProduct

ElementwiseProduct는 각 입력 벡터에 제공된 "가중치" 벡터를 요소별 곱(element-wise multiplication)으로 곱해요. 즉, 데이터셋의 각 컬럼을 스칼라 승수로 스케일링합니다. 이것은 입력 벡터 v와 변환 벡터 scalingVec 사이의 아다마르 곱(Hadamard product)을 나타내어 결과 벡터를 만들어요.

scalingVec을 "w"로 표기하면, 이 변환은 다음과 같이 쓸 수 있어요:

\[ \begin{pmatrix} v_1 \\ \vdots \\ v_N \end{pmatrix} \circ \begin{pmatrix} w_1 \\ \vdots \\ w_N \end{pmatrix} = \begin{pmatrix} v_1 w_1 \\ \vdots \\ v_N w_N \end{pmatrix} \]

ElementwiseProduct는 생성자에 다음 파라미터가 있어요:

  • scalingVec: 변환 벡터.

ElementwiseProductVectorTransformer를 구현해 Vector에 가중치를 적용해 변환된 Vector를 만들거나 RDD[Vector]에 적용해 변환된 RDD[Vector]를 만들 수 있어요.

예제 (Example)

아래 예제는 변환 벡터 값을 사용해 벡터를 변환하는 방법을 보여줘요.

Python:

API에 대한 자세한 내용은 [`ElementwiseProduct` Python 문서](api/python/reference/api/pyspark.mllib.feature.ElementwiseProduct.html)를 참고하세요.
from pyspark.mllib.feature import ElementwiseProduct
from pyspark.mllib.linalg import Vectors

data = sc.textFile("data/mllib/kmeans_data.txt")
parsedData = data.map(lambda x: [float(t) for t in x.split(" ")])

# Create weight vector.
transformingVector = Vectors.dense([0.0, 1.0, 2.0])
transformer = ElementwiseProduct(transformingVector)

# Batch transform
transformedData = transformer.transform(parsedData)
# Single-row transform
transformedData2 = transformer.transform(parsedData.first())
전체 예제 코드는 Spark 저장소의 "examples/src/main/python/mllib/elementwise_product_example.py"에서 확인할 수 있어요.

Scala:

API에 대한 자세한 내용은 [`ElementwiseProduct` Scala 문서](api/scala/org/apache/spark/mllib/feature/ElementwiseProduct.html)를 참고하세요.
import org.apache.spark.mllib.feature.ElementwiseProduct
import org.apache.spark.mllib.linalg.Vectors

// Create some vector data; also works for sparse vectors
val data = sc.parallelize(Seq(Vectors.dense(1.0, 2.0, 3.0), Vectors.dense(4.0, 5.0, 6.0)))

val transformingVector = Vectors.dense(0.0, 1.0, 2.0)
val transformer = new ElementwiseProduct(transformingVector)

// Batch transform and per-row transform give the same results:
val transformedData = transformer.transform(data)
val transformedData2 = data.map(x => transformer.transform(x))
전체 예제 코드는 Spark 저장소의 "examples/src/main/scala/org/apache/spark/examples/mllib/ElementwiseProductExample.scala"에서 확인할 수 있어요.

Java:

API에 대한 자세한 내용은 [`ElementwiseProduct` Java 문서](api/java/org/apache/spark/mllib/feature/ElementwiseProduct.html)를 참고하세요.
import java.util.Arrays;

import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.mllib.feature.ElementwiseProduct;
import org.apache.spark.mllib.linalg.Vector;
import org.apache.spark.mllib.linalg.Vectors;

// Create some vector data; also works for sparse vectors
JavaRDD<Vector> data = jsc.parallelize(Arrays.asList(
  Vectors.dense(1.0, 2.0, 3.0), Vectors.dense(4.0, 5.0, 6.0)));
Vector transformingVector = Vectors.dense(0.0, 1.0, 2.0);
ElementwiseProduct transformer = new ElementwiseProduct(transformingVector);

// Batch transform and per-row transform give the same results:
JavaRDD<Vector> transformedData = transformer.transform(data);
JavaRDD<Vector> transformedData2 = data.map(transformer::transform);
전체 예제 코드는 Spark 저장소의 "examples/src/main/java/org/apache/spark/examples/mllib/JavaElementwiseProductExample.java"에서 확인할 수 있어요.

PCA

PCA를 사용해 벡터를 저차원 공간으로 투영하는 피처 변환기입니다. 자세한 내용은 차원 축소를 참고하세요.

더 알아보기 (Learn more)