rynfkn commited on
Commit
c4814cc
·
1 Parent(s): c54d9bb

add processor

Browse files
processor/__pycache__/image_processor.cpython-312.pyc ADDED
Binary file (2.56 kB). View file
 
processor/__pycache__/tabular_processor.cpython-312.pyc ADDED
Binary file (13.8 kB). View file
 
processor/__pycache__/text_processor.cpython-312.pyc ADDED
Binary file (4.17 kB). View file
 
processor/image_processor.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import numpy as np
3
+ import torch
4
+ from PIL import Image
5
+ from transformers import AutoImageProcessor, AutoModel
6
+
7
+ class ImageProcessor:
8
+ """Processes image data and extracts embeddings"""
9
+ def __init__(self, model_name):
10
+ self.image_processor = AutoImageProcessor.from_pretrained(model_name)
11
+ self.model = AutoModel.from_pretrained(model_name)
12
+ self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
13
+ self.model.to(self.device)
14
+ self.model.eval()
15
+
16
+ def process(self, image_path):
17
+ """Extract image embeddings"""
18
+ # Load and process the image
19
+ image = Image.open(image_path).convert('RGB')
20
+ inputs = self.image_processor(image, return_tensors="pt")
21
+ inputs = {k: v.to(self.device) for k, v in inputs.items()}
22
+
23
+ # Extract embeddings
24
+ with torch.no_grad():
25
+ outputs = self.model(**inputs)
26
+ # DINOv2 uses CLS token embedding
27
+ embedding = outputs.last_hidden_state[:, 0, :].cpu().numpy()
28
+
29
+ # Create feature names and dataframe
30
+ columns = [f'img_emb_{i}' for i in range(embedding.shape[1])]
31
+ return pd.DataFrame(embedding, columns=columns)
processor/tabular_processor.py ADDED
@@ -0,0 +1,223 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import pickle
3
+ from config import SCALER_PATH
4
+
5
+ # Data processing modules
6
+ class TabularProcessor:
7
+ """Processes tabular data with comprehensive manual encoding"""
8
+ def __init__(self, scaler_path=SCALER_PATH):
9
+ # Load the fitted scaler
10
+ with open(scaler_path, 'rb') as f:
11
+ self.scaler = pickle.load(f)
12
+
13
+ # Define complete manual encoding mappings
14
+ self.encoding_mappings = {
15
+ 'Sertifikat': {
16
+ 'HGB': 0, 'Hak Pakai': 1, 'Lain-lain': 2,
17
+ 'SHM': 3, 'Strata Title': 4
18
+ },
19
+ 'Interior': {
20
+ 'Full Furnished': 0, 'Semi Furnished': 1,
21
+ 'Unfurnished': 2, 'Unknown': 3
22
+ },
23
+ 'Orientasi Bangunan': {
24
+ 'Barat': 0, 'Barat Daya': 1, 'Barat Laut': 2,
25
+ 'Hook': 3, 'Selatan': 4, 'Timur': 5,
26
+ 'Timur Laut': 6, 'Unknown': 7, 'Utara': 8
27
+ },
28
+ 'City': {
29
+ 'Malang': 0, 'Sidoarjo': 1, 'Surabaya': 2
30
+ },
31
+ 'District': {
32
+ 'Blimbing': 0, 'Dau': 1, 'Dinoyo': 2, 'Dukuh Pakis': 3,
33
+ 'Gedangan': 4, 'Griya Shanta': 5, 'Gubeng': 6, 'Jatimulyo': 7,
34
+ 'Kedungkandang': 8, 'Kenjeran': 9, 'Lowokwaru': 10,
35
+ 'Malang Kota': 11, 'Merjosari': 12, 'Mojolangu': 13,
36
+ 'Mulyorejo': 14, 'Pakis': 15, 'Pakuwon City': 16,
37
+ 'Pakuwon Indah': 17, 'Permata Jingga': 18, 'Rungkut': 19,
38
+ 'Sidoarjo': 20, 'Soekarno Hatta': 21, 'Sukolilo': 22,
39
+ 'Sukun': 23, 'Surabaya Kota': 24, 'Tenggilis Mejoyo': 25,
40
+ 'Tlogomas': 26, 'Wagir': 27, 'Waru': 28
41
+ },
42
+ 'Nama Perumahan': {
43
+ '-': 0, 'Alana Regency Cemandi': 1, 'Amesta living': 2,
44
+ 'Anggrek Residence': 3, 'Atrani Residence': 4, 'Babatan Pantai': 5,
45
+ 'Barata Jaya': 6, 'Baruk Utara': 7, 'Bratang Binangun': 8,
46
+ 'Citra Garden': 9, 'Citra Garden Sidoarjo': 10, 'Citra Harmoni': 11,
47
+ 'Citra garden': 12, "D'gardenia City": 13, 'DE IMPERIAL ESTATE': 14,
48
+ 'Darmo Permai': 15, 'Dekat Taman Pinang Indah Sidoarjo': 16,
49
+ 'Delta Mandala': 17, 'Deltasari Indah': 18, 'Dharma Husada Mas': 19,
50
+ 'Dharmahusada Mas': 20, 'Dinoyo': 21, 'Dream Park Regency': 22,
51
+ 'Dukuh Kupang': 23, 'Dukuh Kupang Timur soho': 24,
52
+ 'Galaxy Bumi Permai': 25, 'Graha Sukolilo Regency': 26,
53
+ 'Grand Delta Sari': 27, 'Grand Nature Residence': 28,
54
+ 'Green Lake Natural Living': 29, 'Green Orchid Residence': 30,
55
+ 'Griya Permata Gedangan': 31, 'Gunung Anyar Baru': 32,
56
+ 'Gunung Anyar Utara': 33, 'Istana Mentari': 34, 'Jaya Maspion Permata': 35,
57
+ 'Jemursari Regency': 36, 'Jl. Ngagel': 37, 'Joyo Grand': 38,
58
+ 'KECIPIR REGENCY': 39, 'Kahuripan Nirwana': 40, 'Kalijudan': 41,
59
+ 'Kendalsari': 42, 'Klampis Semolo': 43, 'Koala Regency': 44,
60
+ 'Kosagrha': 45, 'Kresna Asri': 46, 'Kupang Baru': 47,
61
+ 'Kutisari Indah Utara': 48, 'Kutisari Selatan': 49,
62
+ 'Kutisari Selatan XIII': 50, 'Kutisri Indah': 51,
63
+ 'Lebak Indah Town House': 52, 'Manyar': 53, 'Manyar Jaya': 54,
64
+ 'Manyar Kertoadi': 55, 'Manyar Tirtoyoso': 56, 'Medayu': 57,
65
+ 'Medayu Utara': 58, 'Medokan Ayu Tambak': 59,
66
+ 'Medokan Sawah Timur Rungkut Surabaya': 60, 'Mojoklangru Kidul': 61,
67
+ 'Mulyosari': 62, 'Mulyosari Utara': 63, 'Mutiara City': 64,
68
+ 'Ngagel Wasana': 65, 'Nginden': 66, 'Nginden Intan Timur': 67,
69
+ 'Nirwana Eksekutif': 68, 'Nirwana Eskekutif': 69, 'Omah View': 70,
70
+ 'Pakisjajar': 71, 'Pakuwon City': 72, 'Pantai Mentari': 73,
71
+ 'Park Regency Keputih': 74, 'Penjaringan Asri': 75,
72
+ 'Penjaringan Sari': 76, 'Pepelegi Indah': 77,
73
+ 'Perum Puri Surya Jaya Cluster Valencia Residence Gedangan Sidoarjo': 78,
74
+ 'Perum perlian kencana sari': 79, 'Perumahan': 80,
75
+ 'Perumahan Bluru Permai Blok C no 11': 81,
76
+ 'Perumahan Dharma Husada Indah': 82, 'Perumahan Green Lake': 83,
77
+ 'Perumahan Griya Amerta': 84, 'Perumahan Griya Galaxy': 85,
78
+ 'Perumahan Griya Pesona Asri': 86, 'Perumahan Istana Safira DAU': 87,
79
+ 'Perumahan Medokan Ayu Surabaya': 88, 'Perumahan Mutiara Regency': 89,
80
+ 'Perumahan Puri Indah Sidoarjo Kota': 90, 'Perumahan Putra Bangsa': 91,
81
+ 'Perumahan Royal Park Regency Rungkut': 92, 'Perumahan Rungkut Mapan': 93,
82
+ 'Perumahan Rungkut Menanggal Harapan Surabaya': 94,
83
+ 'Perumahan Semolowaru Elok': 95, 'Perumahan Semolowaru Indah 2': 96,
84
+ 'Perumahan Taman Pinang Indah': 97,
85
+ 'Perumahan Taman Puspa Anggaswangi': 98, 'Perumahan YKP': 99,
86
+ 'Perumahan river viuw': 100, 'Pondok Candra': 101,
87
+ 'Pondok Candra Indah Waru Rungkut Sidoarjo': 102,
88
+ 'Pondok Chandra': 103, 'Pondok Jati': 104, 'Pondok Mutiara': 105,
89
+ 'Pondok Tjandra': 106, 'Pondok Tjandra Indah': 107,
90
+ 'Prapen indah Kec. Tenggilis Mejoyo Surabaya': 108,
91
+ 'Puri Asri Regency': 109, 'Puri Gunung Anyar': 110,
92
+ 'Puri Indah Lestari': 111, 'Puri Surya Jaya': 112,
93
+ 'Putra Bangsa': 113, 'Rifera Townhouse': 114, 'Rungkut Asri': 115,
94
+ 'Rungkut Asri Utara': 116, 'Rungkut Harapan': 117,
95
+ 'Rungkut Mapan': 118, 'Rungkut Menanggal': 119,
96
+ 'Saphire residence': 120, 'Semampir Tengah': 121,
97
+ 'Semolowaru Elok': 122, 'Sentra Point': 123,
98
+ 'Simpang Darmo Permai Selatan': 124, 'Springville Residence': 125,
99
+ 'Sukolilo Dian Regency 2': 126, 'Sunan Kalijaga': 127,
100
+ 'Sutorejo Prima': 128, 'Sutorejo Prima Indah': 129,
101
+ 'Sutorejo Timur': 130, 'Sutorejo Utara': 131,
102
+ 'TENGGILIS MEJOYO SELATAN': 132, 'Taman Pondok Legi 4': 133,
103
+ 'Taman Rivera Regency': 134, 'Taman pondok indah': 135,
104
+ 'Taman pondok legi': 136, 'Tambak Medokan Ayu': 137,
105
+ 'Tambak medokan ayu VI C': 138, 'Tenggilis Mejoyo': 139,
106
+ 'Unknown': 140, 'Valencia garden , gedangan': 141, 'Vbt': 142,
107
+ 'Vila bukit tidar': 143, 'Villa Kalijudan Indah': 144,
108
+ 'Wellington Park Residence': 145, 'Wisata Semanggi Mangrove': 146,
109
+ 'Wisma Mukti': 147, 'Wisma Permai': 148, 'Wisma Permai Waru': 149,
110
+ 'Wisma Tropodo': 150, 'Wisma permai tengah': 151,
111
+ 'YKP Medokan Asri Rungkut Surabaya Timur': 152,
112
+ 'klampis semolo': 153, 'kompleks mojoarum': 154,
113
+ 'perum jaya maspion permata': 155,
114
+ 'perum taman pinang indah sidoarjo': 156,
115
+ 'regency one east point': 157, 'sukolilo Dian Regency': 158
116
+ }
117
+ }
118
+
119
+ # Default values for unknown categories
120
+ self.default_values = {
121
+ 'Sertifikat': 3, # 'Lain-lain'
122
+ 'Interior': 3, # 'Unknown'
123
+ 'Orientasi Bangunan': 7, # 'Unknown'
124
+ 'City': 0, # 'Malang'
125
+ 'District': 0, # 'Blimbing'
126
+ 'Nama Perumahan': 140 # 'Unknown'
127
+ }
128
+
129
+ # Median/mode values for imputation
130
+ self.imputation_values = {
131
+ 'numerical': {
132
+ 'Luas Bangunan': 138.0, # Will be set during training
133
+ 'Luas Tanah': 120.0,
134
+ 'Daya Listrik': 2200.0,
135
+ 'Tahun Dibangun': 2021,
136
+ 'Latitude' : -7.294603,
137
+ 'Longitude' : 112.769703
138
+
139
+ },
140
+ 'categorical': {
141
+ 'Kamar Tidur': 3,
142
+ 'Kamar Mandi': 2,
143
+ 'Carpots': 1,
144
+ 'Garasi': 1,
145
+ 'Jumlah Lantai': 2
146
+ }
147
+ }
148
+
149
+ def process(self, data):
150
+ """Process tabular data with comprehensive preprocessing"""
151
+ # Convert to DataFrame if needed
152
+ if not isinstance(data, pd.DataFrame):
153
+ data = pd.DataFrame([data])
154
+
155
+ # Ensure all expected columns are present
156
+ expected_cols = [
157
+ 'District', 'City', 'Longitude', 'Latitude', 'Garasi',
158
+ 'Tahun Dibangun', 'Orientasi Bangunan', 'Jumlah Lantai',
159
+ 'Interior', 'Daya Listrik', 'Carpots', 'Sertifikat',
160
+ 'Nama Perumahan', 'Luas Bangunan', 'Luas Tanah',
161
+ 'Kamar Mandi', 'Kamar Tidur'
162
+ ]
163
+
164
+ for col in expected_cols:
165
+ if col not in data.columns:
166
+ raise ValueError(f"Missing required column: {col}")
167
+
168
+ # Apply preprocessing steps
169
+ self._handle_missing_values(data)
170
+ self._apply_manual_encoding(data)
171
+ self._handle_special_cases(data)
172
+
173
+ # Apply the scaler
174
+ scaled_data = self.scaler.transform(data)
175
+ return pd.DataFrame(scaled_data, columns=data.columns)
176
+
177
+ def _handle_missing_values(self, data):
178
+ """Handle missing values according to training logic"""
179
+ # Numerical features
180
+ for col in self.imputation_values['numerical']:
181
+ if col in data.columns and data[col].isna().any():
182
+ data[col].fillna(self.imputation_values['numerical'][col], inplace=True)
183
+
184
+ # Categorical features
185
+ for col in self.imputation_values['categorical']:
186
+ if col in data.columns and data[col].isna().any():
187
+ data[col].fillna(self.imputation_values['categorical'][col], inplace=True)
188
+
189
+ # Special cases
190
+ for col in ['Interior', 'Orientasi Bangunan', 'Nama Perumahan']:
191
+ if col in data.columns and data[col].isna().any():
192
+ data[col].fillna("Unknown", inplace=True)
193
+
194
+ def _apply_manual_encoding(self, data):
195
+ """Apply comprehensive manual encoding"""
196
+ for col, mapping in self.encoding_mappings.items():
197
+ if col in data.columns:
198
+ # Convert to string type for consistent mapping
199
+ data[col] = data[col].astype(str)
200
+ # Handle unknown categories
201
+ data[col] = data[col].apply(
202
+ lambda x: mapping.get(x, self.default_values[col]))
203
+
204
+ def _handle_special_cases(self, data):
205
+ """Handle special cases in the data"""
206
+ # Orientation special values
207
+ if 'Orientasi Bangunan' in data.columns:
208
+ orientation_replace = {'1': 'Unknown', '2': 'Unknown',
209
+ '3': 'Unknown', '4': 'Unknown'}
210
+ data['Orientasi Bangunan'] = data['Orientasi Bangunan'].replace(
211
+ orientation_replace)
212
+ data['Orientasi Bangunan'] = data['Orientasi Bangunan'].map(
213
+ self.encoding_mappings['Orientasi Bangunan'])
214
+
215
+ # Fill any remaining NA values
216
+ for col in data.columns:
217
+ if data[col].isna().any():
218
+ if col in self.default_values:
219
+ data[col].fillna(self.default_values[col], inplace=True)
220
+ elif data[col].dtype.kind in 'biufc': # numeric
221
+ data[col].fillna(0, inplace=True)
222
+ else:
223
+ data[col].fillna("Unknown", inplace=True)
processor/text_processor.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+ import torch
3
+ import numpy as np
4
+ import pandas as pd
5
+ import nltk
6
+ from nltk.tokenize import word_tokenize
7
+ from nltk.corpus import stopwords
8
+ from Sastrawi.Stemmer.StemmerFactory import StemmerFactory
9
+ from transformers import AutoTokenizer, AutoModel
10
+ nltk.download('punkt')
11
+ nltk.download('stopwords')
12
+
13
+ class TextProcessor:
14
+ """Processes text data and extracts embeddings"""
15
+ def __init__(self, model_name):
16
+ self.tokenizer = AutoTokenizer.from_pretrained(model_name)
17
+ self.model = AutoModel.from_pretrained(model_name)
18
+ self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
19
+ self.model.to(self.device)
20
+ self.model.eval()
21
+
22
+ # Initialize Sastrawi stemmer
23
+ factory = StemmerFactory()
24
+ self.stemmer = factory.create_stemmer()
25
+
26
+ def preprocess_text(self, text):
27
+ """Apply text preprocessing"""
28
+ text = text.lower()
29
+ text = re.sub(r'\d+', '', text)
30
+ text = re.sub(r'[^\w\s]', ' ', text)
31
+ text = re.sub(r'\s+', ' ', text).strip()
32
+
33
+ # Tokenize and remove stopwords
34
+ tokens = word_tokenize(text)
35
+ indonesian_stopwords = set(stopwords.words('indonesian'))
36
+ tokens = [word for word in tokens if word not in indonesian_stopwords]
37
+
38
+ # Apply stemming
39
+ tokens = [self.stemmer.stem(word) for word in tokens]
40
+ return ' '.join(tokens)
41
+
42
+ def process(self, texts):
43
+ """Extract text embeddings"""
44
+ if isinstance(texts, str):
45
+ texts = [texts]
46
+
47
+ # Preprocess texts
48
+ processed_texts = [self.preprocess_text(text) for text in texts]
49
+
50
+ # Add E5 prefix
51
+ batch = ["passage: " + text for text in processed_texts]
52
+
53
+ # Tokenize and get embeddings
54
+ inputs = self.tokenizer(
55
+ batch,
56
+ return_tensors="pt",
57
+ truncation=True,
58
+ padding=True,
59
+ max_length=512
60
+ ).to(self.device)
61
+
62
+ with torch.no_grad():
63
+ outputs = self.model(**inputs)
64
+ # E5 uses CLS token embedding
65
+ embeddings = outputs.last_hidden_state[:, 0].cpu().numpy()
66
+
67
+ # Normalize embeddings
68
+ embeddings = embeddings / np.linalg.norm(embeddings, axis=1, keepdims=True)
69
+
70
+ # Create feature names and dataframe
71
+ columns = [f'e5_{i}' for i in range(embeddings.shape[1])]
72
+ return pd.DataFrame(embeddings, columns=columns)