본문 바로가기
DNN with Keras/TensorFlow

[TensorFlow] CSV 전처리 (2)

by goatlab 2022. 6. 16.
728x90
반응형
SMALL

데이터 전처리

 

CSV 파일은 다양한 데이터 유형을 포함할 수 있다. 일반적으로 데이터를 모델에 공급하기 전에 혼합 유형에서 고정 길이 벡터로 변환한다.

 

TensorFlow에는 일반적인 입력 변환을 설명하기 위한 내장 시스템이 있다. 자세한 내용은 tf.feature_column, 이 튜토리얼을 참조하면 된다.

 

원하는 도구 (ex: nltk 또는 sklearn)를 사용하여 데이터를 전처리하고 처리된 출력을 TensorFlow에 전달하면 된다.

 

모델 내에서 전처리를 수행할 때의 주요 이점은 모델을 내보낼 때 전처리가 포함된다는 것이다. 이렇게 하면 원시 데이터를 모델로 직접 전달할 수 있다.

 

연속 데이터

 

데이터가 이미 적절한 숫자 형식인 경우, 데이터를 모델로 전달하기 전에 벡터로 묶을 수 있다.

 
SELECT_COLUMNS = ['survived', 'age', 'n_siblings_spouses', 'parch', 'fare']
DEFAULTS = [0, 0.0, 0.0, 0.0, 0.0]
temp_dataset = get_dataset(train_file_path, 
                           select_columns=SELECT_COLUMNS,
                           column_defaults = DEFAULTS)

show_batch(temp_dataset)
age                 : [44. 28. 40. 28. 29.]
n_siblings_spouses  : [0. 0. 1. 0. 0.]
parch               : [1. 0. 0. 0. 4.]
fare                : [57.979 15.05   9.475  7.229 21.075]
example_batch, labels_batch = next(iter(temp_dataset))

 

다음은 모든 열을 묶는 간단한 함수이다.

 
def pack(features, label):
  return tf.stack(list(features.values()), axis=-1), label

 

이 함수를 데이터세트의 각 요소에 적용한다.

 
packed_dataset = temp_dataset.map(pack)

for features, labels in packed_dataset.take(1):
  print(features.numpy())
  print()
  print(labels.numpy())
[[ 29.      1.      0.     27.721]
 [ 29.      0.      0.    211.337]
 [ 23.      0.      0.      7.854]
 [ 23.      0.      0.     10.5  ]
 [ 33.      0.      2.     26.   ]]

[0 1 0 0 1]

 

혼합 데이터 유형이 있는 경우, 해당 단순 숫자 필드를 분리할 수 있다. tf.feature_column API로 처리할 수 있지만, 약간의 오버헤드가 발생하며 실제로 필요하지 않으면 피해야 한다. 혼합 데이터세트로 다시 전환한다.

 
show_batch(raw_train_data)
sex                 : [b'male' b'male' b'female' b'male' b'male']
age                 : [28. 29.  6.  1. 24.]
n_siblings_spouses  : [0 1 0 4 0]
parch               : [0 0 1 1 0]
fare                : [ 9.5   21.    33.    39.688  7.142]
class               : [b'Third' b'Second' b'Second' b'Third' b'Third']
deck                : [b'unknown' b'unknown' b'unknown' b'unknown' b'unknown']
embark_town         : [b'Southampton' b'Southampton' b'Southampton' b'Southampton'
 b'Southampton']
alone               : [b'y' b'n' b'n' b'n' b'y']
example_batch, labels_batch = next(iter(temp_dataset))

 

따라서, 숫자 특성 목록을 선택하고 단일 열로 묶는 보다 일반적인 전처리기를 정의한다.

 
class PackNumericFeatures(object):
  def __init__(self, names):
    self.names = names

  def __call__(self, features, labels):
    numeric_features = [features.pop(name) for name in self.names]
    numeric_features = [tf.cast(feat, tf.float32) for feat in numeric_features]
    numeric_features = tf.stack(numeric_features, axis=-1)
    features['numeric'] = numeric_features

    return features, labels
NUMERIC_FEATURES = ['age','n_siblings_spouses','parch', 'fare']

packed_train_data = raw_train_data.map(
    PackNumericFeatures(NUMERIC_FEATURES))

packed_test_data = raw_test_data.map(
    PackNumericFeatures(NUMERIC_FEATURES))
show_batch(packed_train_data)
sex                 : [b'male' b'male' b'female' b'male' b'male']
class               : [b'Third' b'Third' b'First' b'Third' b'Third']
deck                : [b'unknown' b'unknown' b'B' b'unknown' b'unknown']
embark_town         : [b'Cherbourg' b'Southampton' b'Southampton' b'Queenstown' b'Queenstown']
alone               : [b'y' b'y' b'y' b'y' b'n']
numeric             : [[ 28.      0.      0.      7.896]
 [ 28.      0.      0.      9.5  ]
 [ 29.      0.      0.    211.337]
 [ 21.      0.      0.      7.733]
 [  4.      4.      1.     29.125]]
example_batch, labels_batch = next(iter(packed_train_data))

 

데이터 정규화

 

연속 데이터는 항상 정규화되어야 한다.

 
import pandas as pd
desc = pd.read_csv(train_file_path)[NUMERIC_FEATURES].describe()
desc

MEAN = np.array(desc.T['mean'])
STD = np.array(desc.T['std'])
def normalize_numeric_data(data, mean, std):
  # Center the data
  return (data-mean)/std

 

이제 숫자 열을 만든다. tf.feature_columns.numeric_column API는 각 배치에서 실행될 normalizer_fn 인수를 허용한다.

 

functools.partial를 사용하여 MEAN  STD를 노멀라이저 fn에 바인딩한다.

 
# See what you just created.
normalizer = functools.partial(normalize_numeric_data, mean=MEAN, std=STD)

numeric_column = tf.feature_column.numeric_column('numeric', normalizer_fn=normalizer, shape=[len(NUMERIC_FEATURES)])
numeric_columns = [numeric_column]
numeric_column
NumericColumn(key='numeric', shape=(4,), default_value=None, dtype=tf.float32, normalizer_fn=functools.partial(<function normalize_numeric_data at 0x7f3d624bdd90>, mean=array([29.631,  0.545,  0.38 , 34.385]), std=array([12.512,  1.151,  0.793, 54.598])))

 

모델을 훈련할 때 이 특성 열을 포함하여 이 숫자 데이터 블록을 선택하고 중앙에 배치한다.

 
example_batch['numeric']
<tf.Tensor: shape=(5, 4), dtype=float32, numpy=
array([[22.  ,  0.  ,  0.  ,  9.35],
       [28.  ,  0.  ,  0.  , 26.55],
       [52.  ,  1.  ,  1.  , 93.5 ],
       [35.  ,  0.  ,  0.  ,  8.05],
       [28.  ,  0.  ,  2.  ,  7.75]], dtype=float32)>
numeric_layer = tf.keras.layers.DenseFeatures(numeric_columns)
numeric_layer(example_batch).numpy()
array([[-0.61 , -0.474, -0.479, -0.459],
       [-0.13 , -0.474, -0.479, -0.144],
       [ 1.788,  0.395,  0.782,  1.083],
       [ 0.429, -0.474, -0.479, -0.482],
       [-0.13 , -0.474,  2.043, -0.488]], dtype=float32)

 

여기에 사용된 평균 기반 정규화를 위해서는 각 열의 평균을 미리 알아야 한다.

 

범주형 데이터

 

CSV 데이터의 일부 열은 범주형 열이다. 즉, 콘텐츠는 제한된 옵션 세트 중 하나여야 합니다.

 

tf.feature_column API를 사용하여 각 범주 열에 대해 tf.feature_column.indicator_column을 가진 모음을 작성한다.

 
CATEGORIES = {
    'sex': ['male', 'female'],
    'class' : ['First', 'Second', 'Third'],
    'deck' : ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'],
    'embark_town' : ['Cherbourg', 'Southhampton', 'Queenstown'],
    'alone' : ['y', 'n']
}
categorical_columns = []
for feature, vocab in CATEGORIES.items():
  cat_col = tf.feature_column.categorical_column_with_vocabulary_list(
        key=feature, vocabulary_list=vocab)
  categorical_columns.append(tf.feature_column.indicator_column(cat_col))
# See what you just created.
categorical_columns
[IndicatorColumn(categorical_column=VocabularyListCategoricalColumn(key='sex', vocabulary_list=('male', 'female'), dtype=tf.string, default_value=-1, num_oov_buckets=0)),
 IndicatorColumn(categorical_column=VocabularyListCategoricalColumn(key='class', vocabulary_list=('First', 'Second', 'Third'), dtype=tf.string, default_value=-1, num_oov_buckets=0)),
 IndicatorColumn(categorical_column=VocabularyListCategoricalColumn(key='deck', vocabulary_list=('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'), dtype=tf.string, default_value=-1, num_oov_buckets=0)),
 IndicatorColumn(categorical_column=VocabularyListCategoricalColumn(key='embark_town', vocabulary_list=('Cherbourg', 'Southhampton', 'Queenstown'), dtype=tf.string, default_value=-1, num_oov_buckets=0)),
 IndicatorColumn(categorical_column=VocabularyListCategoricalColumn(key='alone', vocabulary_list=('y', 'n'), dtype=tf.string, default_value=-1, num_oov_buckets=0))]
categorical_layer = tf.keras.layers.DenseFeatures(categorical_columns)
print(categorical_layer(example_batch).numpy()[0])
[1. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0.]

 

이것은 나중에 모델을 빌드할 때 데이터 처리 입력의 일부가 된다.

 

결합된 전처리 레이어

 

두 개의 특성 열 모음을 추가하고 tf.keras.layers.DenseFeatures에 전달하여 두 입력 유형을 추출하고 전처리할 입력 레이어를 만든다.

 
preprocessing_layer = tf.keras.layers.DenseFeatures(categorical_columns+numeric_columns)
print(preprocessing_layer(example_batch).numpy()[0])
[ 1.     0.     0.     0.     1.     0.     0.     0.     0.     0.

  0.     0.     0.     0.     0.     0.     0.     0.    -0.61  -0.474
 -0.479 -0.459  1.     0.   ]

 

모델 빌드하기

 

preprocessing_layer를 사용하여 tf.keras.Sequential를 빌드한다.

 
model = tf.keras.Sequential([
  preprocessing_layer,
  tf.keras.layers.Dense(128, activation='relu'),
  tf.keras.layers.Dense(128, activation='relu'),
  tf.keras.layers.Dense(1),
])

model.compile(
    loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
    optimizer='adam',
    metrics=['accuracy'])

 

훈련, 평가 및 예측하기

 

이제 모델을 인스턴스화하고 훈련할 수 있다.

 
train_data = packed_train_data.shuffle(500)
test_data = packed_test_data
model.fit(train_data, epochs=20)
Epoch 1/20
WARNING:tensorflow:Layers in a Sequential model should only have a single input tensor, but we receive a <class 'collections.OrderedDict'> input: OrderedDict([('sex', <tf.Tensor 'ExpandDims_4:0' shape=(None, 1) dtype=string>), ('class', <tf.Tensor 'ExpandDims_1:0' shape=(None, 1) dtype=string>), ('deck', <tf.Tensor 'ExpandDims_2:0' shape=(None, 1) dtype=string>), ('embark_town', <tf.Tensor 'ExpandDims_3:0' shape=(None, 1) dtype=string>), ('alone', <tf.Tensor 'ExpandDims:0' shape=(None, 1) dtype=string>), ('numeric', <tf.Tensor 'IteratorGetNext:4' shape=(None, 4) dtype=float32>)])
Consider rewriting this model with the Functional API.
WARNING:tensorflow:Layers in a Sequential model should only have a single input tensor, but we receive a <class 'collections.OrderedDict'> input: OrderedDict([('sex', <tf.Tensor 'ExpandDims_4:0' shape=(None, 1) dtype=string>), ('class', <tf.Tensor 'ExpandDims_1:0' shape=(None, 1) dtype=string>), ('deck', <tf.Tensor 'ExpandDims_2:0' shape=(None, 1) dtype=string>), ('embark_town', <tf.Tensor 'ExpandDims_3:0' shape=(None, 1) dtype=string>), ('alone', <tf.Tensor 'ExpandDims:0' shape=(None, 1) dtype=string>), ('numeric', <tf.Tensor 'IteratorGetNext:4' shape=(None, 4) dtype=float32>)])
Consider rewriting this model with the Functional API.
126/126 [==============================] - 0s 4ms/step - loss: 0.5121 - accuracy: 0.7337
Epoch 2/20
126/126 [==============================] - 0s 3ms/step - loss: 0.4156 - accuracy: 0.8230
Epoch 3/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3967 - accuracy: 0.8246
Epoch 4/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3891 - accuracy: 0.8262
Epoch 5/20
126/126 [==============================] - 0s 4ms/step - loss: 0.3772 - accuracy: 0.8389
Epoch 6/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3725 - accuracy: 0.8437
Epoch 7/20
126/126 [==============================] - 0s 4ms/step - loss: 0.3597 - accuracy: 0.8453
Epoch 8/20
126/126 [==============================] - 0s 4ms/step - loss: 0.3557 - accuracy: 0.8501
Epoch 9/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3602 - accuracy: 0.8437
Epoch 10/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3497 - accuracy: 0.8469
Epoch 11/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3405 - accuracy: 0.8485
Epoch 12/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3427 - accuracy: 0.8469
Epoch 13/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3350 - accuracy: 0.8581
Epoch 14/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3287 - accuracy: 0.8581
Epoch 15/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3277 - accuracy: 0.8549
Epoch 16/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3200 - accuracy: 0.8549
Epoch 17/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3221 - accuracy: 0.8596
Epoch 18/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3250 - accuracy: 0.8612
Epoch 19/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3081 - accuracy: 0.8596
Epoch 20/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3107 - accuracy: 0.8612
<tensorflow.python.keras.callbacks.History at 0x7f3d6257a438>

 

모델이 학습하면 test_data 세트에서 정확성을 확인할 수 있다.

 
test_loss, test_accuracy = model.evaluate(test_data)

print('\n\nTest Loss {}, Test Accuracy {}'.format(test_loss, test_accuracy))
WARNING:tensorflow:Layers in a Sequential model should only have a single input tensor, but we receive a <class 'collections.OrderedDict'> input: OrderedDict([('sex', <tf.Tensor 'ExpandDims_4:0' shape=(None, 1) dtype=string>), ('class', <tf.Tensor 'ExpandDims_1:0' shape=(None, 1) dtype=string>), ('deck', <tf.Tensor 'ExpandDims_2:0' shape=(None, 1) dtype=string>), ('embark_town', <tf.Tensor 'ExpandDims_3:0' shape=(None, 1) dtype=string>), ('alone', <tf.Tensor 'ExpandDims:0' shape=(None, 1) dtype=string>), ('numeric', <tf.Tensor 'IteratorGetNext:4' shape=(None, 4) dtype=float32>)])
Consider rewriting this model with the Functional API.
53/53 [==============================] - 0s 3ms/step - loss: 0.4468 - accuracy: 0.8485


Test Loss 0.4467780292034149, Test Accuracy 0.8484848737716675

 

tf.keras.Model.predict를 사용하여 배치 또는 배치 데이터세트에서 레이블을 유추한다.

 
predictions = model.predict(test_data)

# Show some results
for prediction, survived in zip(predictions[:10], list(test_data)[0][1][:10]):
  prediction = tf.sigmoid(prediction).numpy()
  print("Predicted survival: {:.2%}".format(prediction[0]),
        " | Actual outcome: ",
        ("SURVIVED" if bool(survived) else "DIED"))
WARNING:tensorflow:Layers in a Sequential model should only have a single input tensor, but we receive a <class 'collections.OrderedDict'> input: OrderedDict([('sex', <tf.Tensor 'ExpandDims_4:0' shape=(None, 1) dtype=string>), ('class', <tf.Tensor 'ExpandDims_1:0' shape=(None, 1) dtype=string>), ('deck', <tf.Tensor 'ExpandDims_2:0' shape=(None, 1) dtype=string>), ('embark_town', <tf.Tensor 'ExpandDims_3:0' shape=(None, 1) dtype=string>), ('alone', <tf.Tensor 'ExpandDims:0' shape=(None, 1) dtype=string>), ('numeric', <tf.Tensor 'IteratorGetNext:4' shape=(None, 4) dtype=float32>)])
Consider rewriting this model with the Functional API.
Predicted survival: 98.62%  | Actual outcome:  SURVIVED
Predicted survival: 14.76%  | Actual outcome:  SURVIVED
Predicted survival: 99.91%  | Actual outcome:  DIED
Predicted survival: 70.06%  | Actual outcome:  DIED
Predicted survival: 57.87%  | Actual outcome:  DIED

 

https://www.tensorflow.org/tutorials/load_data/csv?hl=ko#%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A0%84%EC%B2%98%EB%A6%AC 

 

CSV 데이터 로드  |  TensorFlow Core

Google I/O는 끝입니다! TensorFlow 세션 확인하기 세션 보기 CSV 데이터 로드 이 튜토리얼은 파일에서 tf.data.Dataset로 CSV 데이터를 로드하는 방법의 예를 제공합니다. 이 튜토리얼에서 사용된 데이터는

www.tensorflow.org

 

728x90
반응형
LIST