| import pandas as pd
|
| import torch
|
| import numpy as np
|
| from os.path import join
|
| import matplotlib.pyplot as plt
|
| import hydra
|
|
|
|
|
| class QuadTree(object):
|
| def __init__(self, data, mins=None, maxs=None, id="", depth=3, do_split=1000):
|
| self.id = id
|
| self.data = data
|
|
|
| if mins is None:
|
| mins = data[["latitude", "longitude"]].to_numpy().min(0)
|
| if maxs is None:
|
| maxs = data[["latitude", "longitude"]].to_numpy().max(0)
|
|
|
| self.mins = np.asarray(mins)
|
| self.maxs = np.asarray(maxs)
|
| self.sizes = self.maxs - self.mins
|
|
|
| self.children = []
|
|
|
| mids = 0.5 * (self.mins + self.maxs)
|
| xmin, ymin = self.mins
|
| xmax, ymax = self.maxs
|
| xmid, ymid = mids
|
|
|
| if (depth > 0) and (len(self.data) >= do_split):
|
|
|
| data_q1 = data[(data["latitude"] < mids[0]) & (data["longitude"] < mids[1])]
|
| data_q2 = data[
|
| (data["latitude"] < mids[0]) & (data["longitude"] >= mids[1])
|
| ]
|
| data_q3 = data[
|
| (data["latitude"] >= mids[0]) & (data["longitude"] < mids[1])
|
| ]
|
| data_q4 = data[
|
| (data["latitude"] >= mids[0]) & (data["longitude"] >= mids[1])
|
| ]
|
|
|
|
|
| if data_q1.shape[0] > 0:
|
| self.children.append(
|
| QuadTree(
|
| data_q1,
|
| [xmin, ymin],
|
| [xmid, ymid],
|
| id + "0",
|
| depth - 1,
|
| do_split=do_split,
|
| )
|
| )
|
| if data_q2.shape[0] > 0:
|
| self.children.append(
|
| QuadTree(
|
| data_q2,
|
| [xmin, ymid],
|
| [xmid, ymax],
|
| id + "1",
|
| depth - 1,
|
| do_split=do_split,
|
| )
|
| )
|
| if data_q3.shape[0] > 0:
|
| self.children.append(
|
| QuadTree(
|
| data_q3,
|
| [xmid, ymin],
|
| [xmax, ymid],
|
| id + "2",
|
| depth - 1,
|
| do_split=do_split,
|
| )
|
| )
|
| if data_q4.shape[0] > 0:
|
| self.children.append(
|
| QuadTree(
|
| data_q4,
|
| [xmid, ymid],
|
| [xmax, ymax],
|
| id + "3",
|
| depth - 1,
|
| do_split=do_split,
|
| )
|
| )
|
|
|
| def unwrap(self):
|
| if len(self.children) == 0:
|
| return {self.id: [self.mins, self.maxs, self.data.copy()]}
|
| else:
|
| d = dict()
|
| for child in self.children:
|
| d.update(child.unwrap())
|
| return d
|
|
|
|
|
| def extract(qt, name_new_column):
|
| cluster = qt.unwrap()
|
| boundaries, data = {}, []
|
| id_to_quad = np.array(list(cluster.keys()))
|
| for i, (id, vs) in zip(np.arange(len(cluster)), cluster.items()):
|
| (min_lat, min_lon), (max_lat, max_lon), points = vs
|
| points[name_new_column] = int(i)
|
| data.append(points)
|
| boundaries[i] = (
|
| float(min_lat),
|
| float(min_lon),
|
| float(max_lat),
|
| float(max_lon),
|
| points["latitude"].mean(),
|
| points["longitude"].mean(),
|
| )
|
|
|
| data = pd.concat(data)
|
| return boundaries, data, id_to_quad
|
|
|
|
|
| def vizu(name_new_column, df_train, boundaries, save_path):
|
| plt.hist(df_train[name_new_column], bins=len(boundaries))
|
| plt.xlabel("Cluster ID")
|
| plt.ylabel("Number of images")
|
| plt.title("Cluster distribution")
|
| plt.yscale("log")
|
| plt.savefig(join(save_path, f"{name_new_column}_distrib.png"))
|
| plt.clf()
|
|
|
| plt.scatter(
|
| df_train["longitude"].to_numpy(),
|
| df_train["latitude"].to_numpy(),
|
| c=np.random.permutation(len(boundaries))[df_train[name_new_column].to_numpy()],
|
| cmap="tab20",
|
| s=0.1,
|
| alpha=0.5,
|
| )
|
| plt.xlabel("Longitude")
|
| plt.ylabel("Latitude")
|
| plt.title("Quadtree map")
|
| plt.savefig(join(save_path, f"{name_new_column}_map.png"))
|
|
|
|
|
| @hydra.main(
|
| config_path="../../configs/scripts",
|
| config_name="preprocess",
|
| version_base=None,
|
| )
|
| def main(cfg):
|
| data_path = join(cfg.data_dir, "osv5m")
|
| save_path = cfg.data_dir
|
| name_new_column = f"quadtree_{cfg.depth}_{cfg.do_split}"
|
|
|
|
|
| train_fp = join(data_path, f"train.csv")
|
| df_train = pd.read_csv(train_fp, low_memory=False)
|
|
|
| qt = QuadTree(df_train, depth=cfg.depth, do_split=cfg.do_split)
|
| boundaries, df_train, id_to_quad = extract(qt, name_new_column)
|
|
|
| vizu(name_new_column, df_train, boundaries, save_path)
|
|
|
|
|
| boundaries = pd.DataFrame.from_dict(
|
| boundaries,
|
| orient="index",
|
| columns=["min_lat", "min_lon", "max_lat", "max_lon", "mean_lat", "mean_lon"],
|
| )
|
| boundaries.to_csv(
|
| join(save_path, f"{name_new_column}.csv"), index_label="cluster_id"
|
| )
|
|
|
|
|
| test_fp = join(data_path, f"test.csv")
|
| df_test = pd.read_csv(test_fp)
|
|
|
| above_lat = np.expand_dims(df_test["latitude"].to_numpy(), -1) > np.expand_dims(
|
| boundaries["min_lat"].to_numpy(), 0
|
| )
|
| below_lat = np.expand_dims(df_test["latitude"].to_numpy(), -1) < np.expand_dims(
|
| boundaries["max_lat"].to_numpy(), 0
|
| )
|
| above_lon = np.expand_dims(df_test["longitude"].to_numpy(), -1) > np.expand_dims(
|
| boundaries["min_lon"].to_numpy(), 0
|
| )
|
| below_lon = np.expand_dims(df_test["longitude"].to_numpy(), -1) < np.expand_dims(
|
| boundaries["max_lon"].to_numpy(), 0
|
| )
|
|
|
| mask = np.logical_and(
|
| np.logical_and(above_lat, below_lat), np.logical_and(above_lon, below_lon)
|
| )
|
|
|
| df_test[name_new_column] = np.argmax(mask, axis=1)
|
|
|
|
|
| lat = torch.tensor(boundaries["mean_lat"])
|
| lon = torch.tensor(boundaries["mean_lon"])
|
| coord = torch.stack([lat, lon], dim=-1)
|
| torch.save(
|
| coord, join(save_path, f"index_to_gps_quadtree_{cfg.depth}_{cfg.do_split}.pt")
|
| )
|
|
|
| torch.save(id_to_quad, join(save_path, f"id_to_quad_{cfg.depth}_{cfg.do_split}.pt"))
|
|
|
| if cfg.overwrite_csv:
|
| df_train.to_csv(train_fp, index=False)
|
| df_test.to_csv(test_fp, index=False)
|
|
|
| df = pd.read_csv(join(data_path, "train.csv"), low_memory=False).fillna("NaN")
|
|
|
| country_avg = (
|
| df.groupby("unique_country")[["latitude", "longitude"]].mean().reset_index()
|
| )
|
| country_avg.to_csv(
|
| join(save_path, "country_center.csv"),
|
| columns=["unique_country", "latitude", "longitude"],
|
| index=False,
|
| )
|
|
|
| region_avg = (
|
| df.groupby(["unique_region"])[["latitude", "longitude"]].mean().reset_index()
|
| )
|
| region_avg.to_csv(
|
| join(save_path, "region_center.csv"),
|
| columns=["unique_region", "latitude", "longitude"],
|
| index=False,
|
| )
|
|
|
| area_avg = (
|
| df.groupby(["unique_sub-region"])[["latitude", "longitude"]]
|
| .mean()
|
| .reset_index()
|
| )
|
| area_avg.to_csv(
|
| join(save_path, "sub-region_center.csv"),
|
| columns=["unique_sub-region", "latitude", "longitude"],
|
| index=False,
|
| )
|
|
|
| city_avg = (
|
| df.groupby(["unique_city"])[["latitude", "longitude"]].mean().reset_index()
|
| )
|
| city_avg.to_csv(
|
| join(save_path, "city_center.csv"),
|
| columns=["unique_city", "latitude", "longitude"],
|
| index=False,
|
| )
|
|
|
| for class_name in [
|
| "unique_country",
|
| "unique_sub-region",
|
| "unique_region",
|
| "unique_city",
|
| ]:
|
|
|
| csv_file = class_name.split("_")[-1] + "_center.csv"
|
| df = pd.read_csv(join(save_path, csv_file), low_memory=False)
|
|
|
| splits = ["train"]
|
| categories = sorted(
|
| pd.concat(
|
| [
|
| pd.read_csv(
|
| join(data_path, f"{split}.csv"), low_memory=False
|
| )[class_name]
|
| for split in splits
|
| ]
|
| )
|
| .fillna("NaN")
|
| .unique()
|
| .tolist()
|
| )
|
|
|
| if "NaN" in categories:
|
| categories.remove("NaN")
|
|
|
|
|
| num_classes = len(categories)
|
|
|
|
|
| category_to_index = {category: i for i, category in enumerate(categories)}
|
|
|
| dictionary = torch.zeros((num_classes, 2))
|
| for index, row in df.iterrows():
|
| key = row.iloc[0]
|
| value = [row.iloc[1], row.iloc[2]]
|
| if key in categories:
|
| (
|
| dictionary[category_to_index[key], 0],
|
| dictionary[category_to_index[key], 1],
|
| ) = np.radians(row.iloc[1]), np.radians(row.iloc[2])
|
|
|
|
|
| output_file = join(save_path, "index_to_gps_" + class_name + ".pt")
|
| torch.save(dictionary, output_file)
|
|
|
| train = pd.read_csv(join(data_path, "train.csv"), low_memory=False).fillna(
|
| "NaN"
|
| )
|
|
|
| u = train.groupby("unique_city").sample(n=1)
|
|
|
| country_df = (
|
| u.pivot(index="unique_city", columns="unique_country", values="unique_city")
|
| .notna()
|
| .astype(int)
|
| .fillna(0)
|
| )
|
| country_to_idx = {
|
| category: i for i, category in enumerate(list(country_df.columns))
|
| }
|
| city_country_matrix = torch.tensor(country_df.values) / 1.0
|
|
|
| region_df = (
|
| u.pivot(index="unique_city", columns="unique_region", values="unique_city")
|
| .notna()
|
| .astype(int)
|
| .fillna(0)
|
| )
|
| region_to_idx = {category: i for i, category in enumerate(list(region_df.columns))}
|
| city_region_matrix = torch.tensor(region_df.values) / 1.0
|
|
|
| country_df = (
|
| u.pivot(index="unique_city", columns="unique_country", values="unique_city")
|
| .notna()
|
| .astype(int)
|
| .fillna(0)
|
| )
|
| country_to_idx = {
|
| category: i for i, category in enumerate(list(country_df.columns))
|
| }
|
| city_country_matrix = torch.tensor(country_df.values) / 1.0
|
|
|
| output_file = join(save_path, "city_to_country.pt")
|
| torch.save(city_country_matrix, output_file)
|
|
|
| output_file = join(save_path, "country_to_idx.pt")
|
| torch.save(country_to_idx, output_file)
|
|
|
| region_df = (
|
| u.pivot(index="unique_city", columns="unique_region", values="unique_city")
|
| .notna()
|
| .astype(int)
|
| .fillna(0)
|
| )
|
| region_to_idx = {category: i for i, category in enumerate(list(region_df.columns))}
|
| city_region_matrix = torch.tensor(region_df.values) / 1.0
|
|
|
| output_file = join(save_path, "city_to_region.pt")
|
| torch.save(city_region_matrix, output_file)
|
|
|
| output_file = join(save_path, "region_to_idx.pt")
|
| torch.save(region_to_idx, output_file)
|
|
|
| area_df = (
|
| u.pivot(index="unique_city", columns="unique_sub-region", values="unique_city")
|
| .notna()
|
| .astype(int)
|
| .fillna(0)
|
| )
|
| area_to_idx = {category: i for i, category in enumerate(list(area_df.columns))}
|
| city_area_matrix = torch.tensor(area_df.values) / 1.0
|
|
|
| output_file = join(save_path, "city_to_area.pt")
|
| torch.save(city_area_matrix, output_file)
|
|
|
| output_file = join(save_path, "area_to_idx.pt")
|
| torch.save(area_to_idx, output_file)
|
| gt = torch.load(join(save_path, f"id_to_quad_{cfg.depth}_{cfg.do_split}.pt"))
|
| matrixes = []
|
| dicts = []
|
| for i in range(1, cfg.depth):
|
|
|
| l = [s[: cfg.depth - i] if len(s) >= cfg.depth + 1 - i else s for s in gt]
|
|
|
|
|
| h = list(set(l))
|
|
|
|
|
| h_dict = {value: index for index, value in enumerate(h)}
|
| dicts.append(h_dict)
|
|
|
|
|
| matrix = torch.zeros((len(gt), len(h)))
|
|
|
|
|
| for h in range(len(gt)):
|
| j = h_dict[l[h]]
|
| matrix[h, j] = 1
|
| matrixes.append(matrix)
|
|
|
| output_file = join(save_path, "quadtree_matrixes.pt")
|
| torch.save(matrixes, output_file)
|
|
|
| output_file = join(save_path, "quadtree_dicts.pt")
|
| torch.save(dicts, output_file)
|
|
|
|
|
| if __name__ == "__main__":
|
| main()
|
|
|