Repository: mie-lab/trackintel

Issue:
BUG: generate_staypoints and generate_trips
if the input pfs already has a column `staypoint_id`, the following error will occur on Line 144

`ValueError: columns overlap but no suffix specified: Index(['staypoint_id'], dtype='object')`

Comments:

Patch:
diff --git a/trackintel/preprocessing/positionfixes.py b/trackintel/preprocessing/positionfixes.py
index 650c5a3..46afbf9 100644
--- a/trackintel/preprocessing/positionfixes.py
+++ b/trackintel/preprocessing/positionfixes.py
@@ -85,6 +85,10 @@ def generate_staypoints(
     # copy the original pfs for adding 'staypoint_id' column
     pfs = pfs_input.copy()
 
+    # if the positionfixes already have a column "staypoint_id", we drop it
+    if "staypoint_id" in pfs:
+        pfs.drop(columns="staypoint_id", inplace=True)
+
     elevation_flag = "elevation" in pfs.columns  # if there is elevation data
 
     geo_col = pfs.geometry.name
@@ -214,6 +218,10 @@ def generate_triplegs(pfs_input, stps_input, method="between_staypoints", gap_th
     # copy the original pfs for adding 'staypoint_id' column
     pfs = pfs_input.copy()
 
+    # if the positionfixes already have a column "tripleg_id", we drop it
+    if "tripleg_id" in pfs:
+        pfs.drop(columns="tripleg_id", inplace=True)
+
     if method == "between_staypoints":
 
         # get case:
diff --git a/trackintel/preprocessing/triplegs.py b/trackintel/preprocessing/triplegs.py
index 066c95b..f599a38 100644
--- a/trackintel/preprocessing/triplegs.py
+++ b/trackintel/preprocessing/triplegs.py
@@ -91,6 +91,15 @@ def generate_trips(stps_input, tpls_input, gap_threshold=15, print_progress=Fals
     tpls = tpls_input.copy()
     stps = stps_input.copy()
 
+    # if the triplegs already have a column "trip_id", we drop it
+    if "trip_id" in tpls:
+        tpls.drop(columns="trip_id", inplace=True)
+
+    # if the staypoints already have any of the columns  "trip_id", "prev_trip_id", "next_trip_id", we drop them
+    for col in ["trip_id", "prev_trip_id", "next_trip_id"]:
+        if col in stps:
+            stps.drop(columns=col, inplace=True)
+
     tpls["type"] = "tripleg"
     stps["type"] = "staypoint"
 


Test patch:
diff --git a/tests/preprocessing/test_positionfixes.py b/tests/preprocessing/test_positionfixes.py
index b4664ca..e16b9a9 100644
--- a/tests/preprocessing/test_positionfixes.py
+++ b/tests/preprocessing/test_positionfixes.py
@@ -23,6 +23,20 @@ def geolife_pfs_stps_long():
 class TestGenerate_staypoints:
     """Tests for generate_staypoints() method."""
 
+    def test_duplicate_columns(self):
+        """Test if running the function twice, the generated column does not yield exception in join statement"""
+
+        # we run generate_staypoints twice in order to check that the extra column(tripleg_id) does
+        # not cause any problems in the second run
+        pfs, _ = ti.io.dataset_reader.read_geolife(os.path.join("tests", "data", "geolife"))
+        pfs_run_1, _ = pfs.as_positionfixes.generate_staypoints(
+            method="sliding", dist_threshold=100, time_threshold=5.0, include_last=True
+        )
+        pfs_run_2, _ = pfs_run_1.as_positionfixes.generate_staypoints(
+            method="sliding", dist_threshold=100, time_threshold=5.0, include_last=True
+        )
+        assert set(pfs_run_1.columns) == set(pfs_run_2.columns)
+
     def test_sliding_min(self):
         """Test if using small thresholds, stp extraction yields each pfs."""
         pfs, _ = ti.io.dataset_reader.read_geolife(os.path.join("tests", "data", "geolife"))
@@ -123,6 +137,17 @@ class TestGenerate_staypoints:
 class TestGenerate_triplegs:
     """Tests for generate_triplegs() method."""
 
+    def test_duplicate_columns(self, geolife_pfs_stps_long):
+        """Test if running the function twice, the generated column does not yield exception in join statement"""
+
+        # we run generate_triplegs twice in order to check that the extra column (tripleg_id) does
+        # not cause any problems in the second run
+        pfs, stps = geolife_pfs_stps_long
+
+        pfs_run_1, _ = pfs.as_positionfixes.generate_triplegs(stps, method="between_staypoints")
+        pfs_run_2, _ = pfs_run_1.as_positionfixes.generate_triplegs(stps, method="between_staypoints")
+        assert set(pfs_run_1.columns) == set(pfs_run_2.columns)
+
     def test_user_without_stps(self, geolife_pfs_stps_long):
         """Check if it is safe to have users that have pfs but no stps."""
         pfs, stps = geolife_pfs_stps_long
diff --git a/tests/preprocessing/test_triplegs.py b/tests/preprocessing/test_triplegs.py
index 76d793a..40e3388 100644
--- a/tests/preprocessing/test_triplegs.py
+++ b/tests/preprocessing/test_triplegs.py
@@ -29,6 +29,24 @@ class TestSmoothen_triplegs:
 class TestGenerate_trips:
     """Tests for generate_trips() method."""
 
+    def test_duplicate_columns(self):
+        """Test if running the function twice, the generated column does not yield exception in join statement"""
+        # load pregenerated trips
+        trips_loaded = ti.read_trips_csv(os.path.join("tests", "data", "geolife_long", "trips.csv"), index_col="id")
+
+        # create trips from geolife (based on positionfixes)
+        pfs, _ = ti.io.dataset_reader.read_geolife(os.path.join("tests", "data", "geolife_long"))
+        pfs, stps = pfs.as_positionfixes.generate_staypoints(method="sliding", dist_threshold=25, time_threshold=5)
+        stps = stps.as_staypoints.create_activity_flag(time_threshold=15)
+        pfs, tpls = pfs.as_positionfixes.generate_triplegs(stps)
+
+        # generate trips and a joint staypoint/triplegs dataframe
+        stps_run_1, tpls_run_1, _ = ti.preprocessing.triplegs.generate_trips(stps, tpls, gap_threshold=15)
+        stps_run_2, tpls_run_2, _ = ti.preprocessing.triplegs.generate_trips(stps_run_1, tpls_run_1, gap_threshold=15)
+
+        assert set(tpls_run_1.columns) == set(tpls_run_2.columns)
+        assert set(stps_run_1.columns) == set(stps_run_2.columns)
+
     def test_generate_trips(self):
         """Test if we can generate the example trips based on example data."""
         # load pregenerated trips