<jupyter_start><jupyter_text>1. Feature engineering (data preparation)<jupyter_code>df = pd.read_csv('NYCTaxiFares.csv')
df.head(4)
df['fare_amount'].describe()<jupyter_output><empty_output><jupyter_text>Calculate the distance traveledThe haversine formula calculates the distance on a sphere between two sets of GPS coordinates.Here we assign latitude values with $\varphi$ (phi) and longitude with $\lambda$ (lambda).The distance formula works out to${\displaystyle d=2r\arcsin \left({\sqrt {\sin ^{2}\left({\frac {\varphi _{2}-\varphi _{1}}{2}}\right)+\cos(\varphi _{1})\:\cos(\varphi _{2})\:\sin ^{2}\left({\frac {\lambda _{2}-\lambda _{1}}{2}}\right)}}\right)}$where$\begin{split} r&: \textrm {radius of the sphere (Earth's radius averages 6371 km)}\\\varphi_1, \varphi_2&: \textrm {latitudes of point 1 and point 2}\\\lambda_1, \lambda_2&: \textrm {longitudes of point 1 and point 2}\end{split}$<jupyter_code>def haversine_distance(df, lat1, long1, lat2, long2):
    '''Haversine distance - distance calculated with a formula giving between two points given by GPS'''
    r = 6371 # average radius of Earth in km

    phi1 = np.radians(df[lat1])
    phi2 = np.radians(df[lat2])

    delta_phi = np.radians(df[lat2] - df[lat1])
    delta_lambda = np.radians(df[long2] - df[long1])

    a = np.sin(delta_phi / 2) ** 2 + np.cos(phi1) * np.cos(phi2) * np.sin(delta_lambda / 2) **2
    c = 2 * np.arctan2(np.sqrt(a), np.sqrt(1 - a))
    d = (r * c)

    return d
df.columns
df['dist_km'] = haversine_distance(df, 'pickup_latitude', 'pickup_longitude', 'dropoff_latitude', 'dropoff_longitude')
df.head(4)
df.info()
df['pickup_datetime'] = pd.to_datetime(df['pickup_datetime'])
df.info()
df.head(4)<jupyter_output><empty_output><jupyter_text>--- What is possible to do with timestamp object<jupyter_code>my_time = df['pickup_datetime'][0]
my_time
my_time.hour<jupyter_output><empty_output><jupyter_text>---<jupyter_code>df['EDTdate'] = df['pickup_datetime'] - pd.Timedelta(hours=4)
df['Hour'] = df['EDTdate'].dt.hour
df['AMorPM'] = np.where(df['Hour'] < 12, 'am', 'pm')
df['Weekday'] = df['EDTdate'].dt.strftime('%a')
df.head(4)<jupyter_output><empty_output><jupyter_text>Split for categorical and continous columns<jupyter_code>cat_cols = ['Hour', 'AMorPM', 'Weekday']
con_cols = ['pickup_longitude','pickup_latitude', 'dropoff_longitude', 'dropoff_latitude', 'passenger_count', 'dist_km']
y_col = ['fare_amount']
# convert categorical to numeric codes with pandas

for cat in cat_cols:
    df[cat] = df[cat].astype('category')
df.dtypes
df['Hour'].head(4)
df['Hour'].cat.categories
df['Hour'].cat.codes[:4].values
hr = df['Hour'].cat.codes.values
ampm = df['AMorPM'].cat.codes.values
wkdy = df['Weekday'].cat.codes.values
hr
# stack arrays into one tensor
cats = np.stack([hr, ampm, wkdy], axis=1)
cats.shape
# cats = np.stack([df[col].cat.values for col in cat_cols], 1)
cats = torch.tensor(cats, dtype=torch.int64)
conts = np.stack([df[col].values for col in con_cols], 1)
conts.shape
conts = torch.tensor(conts, dtype=torch.float)
y = torch.tensor(df[y_col].values, dtype=torch.float)
y[:3], y.shape<jupyter_output><empty_output><jupyter_text>Embedding<jupyter_code>category_sizes = [len(df[col].cat.categories) for col in cat_cols]
category_sizes
embedded_sizes = [(size, min(50, (size+1)//2)) for size in category_sizes]
embedded_sizes<jupyter_output><empty_output><jupyter_text>Tabular model ---<jupyter_code>catz = cats[:4]
catz
self_embeds = nn.ModuleList([nn.Embedding(ni, nf) for ni, nf in embedded_sizes])
self_embeds
embeddingz = []

for i, e in enumerate(self_embeds):
    embeddingz.append(e(catz[:, i]))

embeddingz
z = torch.cat(embeddingz, 1)
z
# creating a dropout layer
self_embeds_drop = nn.Dropout(0.4)
z = self_embeds_drop(z)
z<jupyter_output><empty_output><jupyter_text>---  Building tabular model<jupyter_code>class TabularModel(nn.Module):
    def __init__(self, embeds_size, n_continous, out_size, layers, p=0.5): # p is probability of dropout
        super().__init__()

        self.embeds = nn.ModuleList([nn.Embedding(ni, nf) for ni, nf in embeds_size])
        self.emb_drop = nn.Dropout(p)
        self.batch_norm = nn.BatchNorm1d(n_continous)

        layerlist = []
        n_embeds = sum([nf for ni, nf in embeds_size])
        n_in = n_embeds + n_continous

        for i in layers:
            layerlist.append(nn.Linear(n_in, i))
            layerlist.append(nn.ReLU(inplace=True))
            layerlist.append(nn.BatchNorm1d(i))
            layerlist.append(nn.Dropout(p))
            n_in = i
        layerlist.append(nn.Linear(layers[-1], out_size))

        self.layers = nn.Sequential(*layerlist)

    def forward(self, x_cat, x_cont):
        embeddings = []

        for i, e in enumerate(self.embeds):
            embeddings.append(e(x_cat[:, i]))
        
        x = torch.cat(embeddings, 1)
        x = self.emb_drop(x)

        x_cont = self.batch_norm(x_cont)
        x = torch.cat([x, x_cont], 1)
        x = self.layers(x)
        
        return x
torch.manual_seed(33)

model = TabularModel(embedded_sizes, conts.shape[1], 1, [200, 100], p=0.4)
model
criterion = nn.MSELoss()    # sqrt(MSE) is RMSE
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
batch_size = 60000
test_size = int(batch_size * 0.2)
cat_train = cats[:batch_size-test_size]
cat_test = cats[batch_size-test_size:batch_size]
con_train = conts[:batch_size-test_size]
con_test = conts[batch_size-test_size:batch_size]
y_train = y[:batch_size-test_size]
y_test = y[batch_size-test_size:batch_size]
len(cat_train), len(con_train), len(cat_test), len(con_test), len(y_train), len(y_test)
import time

start_time = time.time()

epochs = 300

losses = []

for i in range(epochs):
    i += 1

    y_pred = model(cat_train, con_train)
    loss = torch.sqrt(criterion(y_pred, y_train)) # RMSE
    losses.append(loss.detach().float())

    if i % 25 == 1:
        print(f'Loss at epoch {i} = {loss:.4f}')
    
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

duration = time.time() - start_time

print(f'Training took {duration//60} minutes')
plt.plot(range(epochs), losses)
with torch.no_grad():

    y_val = model(cat_test, con_test)
    loss = torch.sqrt(criterion(y_val, y_test))

loss
for i in range(10):
    print(f'{i}. Predicted: {y_val[i].item():12.4f} - True: {y_test[i].item():12.4f}')
torch.save(model.state_dict(), 'taxi_model.pt')<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.15860885839051778, 'fraction_numerical': 0.018558951965065504, 'mean_word_length': 4.476515798462852, 'pattern_counts': {'":': 0, '<': 34, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '8', 'dir': 'jupyter-structured-clean-dedup', 'id': '458178', 'license': 'MIT', 'n_tokens_mistral': 2498, 'n_tokens_neox': 2403, 'n_words': 487, 'path': 'Courses/PyTorch for Deep Learning with Python/07 ANN/046_ANN_regression.ipynb', 'repo_name': 'industArk/AI_learn', 'size': '6412'}