Edit on GitHub

vse_sim.simulation

  1import csv
  2import os
  3import random
  4from uuid import uuid4
  5
  6from .debug_dump import debug, setDebug
  7from .decorators import autoassign
  8from .methods import (
  9    IRNR,
 10    V321,
 11    Borda,
 12    BulletyApprovalWith,
 13    Irv,
 14    IrvPrime,
 15    Mav,
 16    Mj,
 17    Plurality,
 18    Rp,
 19    Schulze,
 20    Score,
 21    Srv,
 22)
 23from .strategies import LazyChooser, OssChooser, ProbChooser, beHon, beStrat, beX, truth
 24from .voter_models import PolyaModel  # noqa: F401 - used by doctests
 25
 26
 27def uniquify(seq):
 28    # order preserving
 29    checked = []
 30    for e in seq:
 31        if e not in checked:
 32            checked.append(e)
 33    return checked
 34
 35
 36class CsvBatch:
 37    @autoassign
 38    def __init__(
 39        self,
 40        model,
 41        methods,
 42        nvot,
 43        ncand,
 44        niter,
 45        baseName=None,
 46        media=truth,
 47        seed=None,
 48        force=False,
 49    ):
 50        """A harness function which creates niter elections from model and finds three kinds
 51        of utility for all methods given.
 52
 53        for instance:
 54
 55        >>> csvs = CsvBatch(PolyaModel(), [[Score(), baseRuns], [Mav(), medianRuns]], nvot=5, ncand=4, niter=3)
 56        >>> len(csvs.rows)
 57        60
 58        """
 59        rows = []
 60        emodel = str(model)
 61        if seed is None:
 62            seed = (baseName or "") + str(niter)
 63            self.seed = seed
 64        random.seed(seed)
 65        try:
 66            from git import Repo
 67
 68            repo = Repo(os.getcwd())
 69            if not force:
 70                assert not repo.is_dirty()
 71            self.repo_version = repo.head.commit.hexsha
 72        except Exception:
 73            self.repo_version = "unknown repo version"
 74        for i in range(niter):
 75            eid = uuid4()
 76            electorate = model(nvot, ncand)
 77            for method, chooserFuns in methods:
 78                results = method.resultsTable(
 79                    eid, emodel, ncand, electorate, chooserFuns, media=media
 80                )
 81                rows.extend(results)
 82            debug(i, results[1:3])
 83        self.rows = rows
 84        if baseName:
 85            self.saveFile(baseName)
 86
 87    def saveFile(self, baseName="SimResults"):
 88        """print the result of doVse in an accessible format.
 89        for instance:
 90
 91        csvs.saveFile()
 92        """
 93        i = 1
 94        while os.path.isfile(baseName + str(i) + ".csv"):
 95            i += 1
 96        keys = ["vse", "method", "chooser", *list(self.rows[0].keys())]
 97        for n in range(4):
 98            keys.extend([f"tallyName{str(n)}", f"tallyVal{str(n)}"])
 99        keys = uniquify(keys)
100        path = baseName + str(i) + ".csv"
101        with open(path, "w") as myFile:
102            print(
103                f"# {dict(media=self.media.__name__, version=self.repo_version, seed=self.seed, model=self.model, methods=self.methods, nvot=self.nvot, ncand=self.ncand, niter=self.niter)}",
104                file=myFile,
105            )
106
107            dw = csv.DictWriter(myFile, keys, restval="NA")
108            dw.writeheader()
109            for r in self.rows:
110                dw.writerow(r)
111        return path
112
113    @property
114    def results(self):
115        """Return this batch as a pandas-backed ``VseResults`` object."""
116        from .dataframe import VseResults
117
118        return VseResults.from_rows(self.rows)
119
120    @property
121    def dataframe(self):
122        """Return this batch's rows as a pandas DataFrame."""
123        return self.to_dataframe()
124
125    @property
126    def df(self):
127        """Alias for ``dataframe``."""
128        return self.dataframe
129
130    def to_dataframe(self, copy=True):
131        """Return this batch's rows as a pandas DataFrame."""
132        return self.results.to_dataframe(copy=copy)
133
134    def summarize(self, group_by=("method", "chooser"), sort_by="mean_vse", ascending=False):
135        """Return a pandas DataFrame summarizing VSE scores for this batch."""
136        return self.results.summarize(
137            group_by=group_by,
138            sort_by=sort_by,
139            ascending=ascending,
140        )
141
142    def report(self, group_by=("method", "chooser")):
143        """Return common pandas report tables for this batch."""
144        return self.results.report(group_by=group_by)
145
146    def plot_vse(self, *args, **kwargs):
147        """Plot summarized VSE scores for this batch."""
148        return self.results.plot_vse(*args, **kwargs)
149
150
151medianRuns = [
152    OssChooser([beHon, ProbChooser([(1 / 2, beStrat), (1 / 2, beHon)])]),
153    ProbChooser([(1 / 4, beX), (3 / 4, beHon)]),
154    ProbChooser([(1 / 2, beX), (1 / 2, beHon)]),
155    ProbChooser([(3 / 4, beX), (1 / 4, beHon)]),
156    ProbChooser([(0.5, beStrat), (0.5, beHon)]),
157    ProbChooser([(1 / 3, beStrat), (1 / 3, beHon), (1 / 3, beX)]),
158    LazyChooser(),
159    ProbChooser([(1 / 2, LazyChooser()), (1 / 2, beHon)]),
160]
161
162baseRuns = [
163    OssChooser([beHon, ProbChooser([(1 / 2, beStrat), (1 / 2, beHon)])]),
164    ProbChooser([(1 / 4, beStrat), (3 / 4, beHon)]),
165    ProbChooser([(1 / 2, beStrat), (1 / 2, beHon)]),
166    ProbChooser([(3 / 4, beStrat), (1 / 4, beHon)]),
167]
168
169allSystems = [
170    [Score(1000), baseRuns],
171    [Score(10), baseRuns],
172    [Score(2), baseRuns],
173    [Score(1), baseRuns],
174    [BulletyApprovalWith(0.6), baseRuns],
175    [Srv(10), baseRuns],
176    [Srv(2), baseRuns],
177    [Plurality(), baseRuns],
178    [Borda(), baseRuns],
179    [Irv(), baseRuns],
180    [IrvPrime(), baseRuns],
181    [Schulze(), baseRuns],
182    [Rp(), baseRuns],
183    [V321(), baseRuns],
184    [Mav(), medianRuns],
185    [Mj(), medianRuns],
186    [IRNR(), baseRuns],
187]
188
189# request from Mark: "SRV0-2, SRV0-3, SRV0-4, SRV0-5, SRV0-6, SRV0-7, SRV0-8, SRV0-9, SRV0-10, Score0-10, 321, Approval, IRV and plurality"
190markMethods = [
191    [Srv(2), baseRuns],
192    [Srv(3), baseRuns],
193    [Srv(4), baseRuns],
194    [Srv(5), baseRuns],
195    [Srv(6), baseRuns],
196    [Srv(7), baseRuns],
197    [Srv(8), baseRuns],
198    [Srv(9), baseRuns],
199    [Score(10), baseRuns],
200    [V321(), baseRuns],
201    [BulletyApprovalWith(0.6), baseRuns],
202    [Irv(), baseRuns],
203    [Plurality(), baseRuns],
204]
205
206
207def run_simulation(
208    model,
209    methods,
210    nvot,
211    ncand,
212    niter,
213    baseName=None,
214    media=truth,
215    seed=None,
216    force=False,
217):
218    """Run a simulation and return a pandas-backed ``VseResults`` object."""
219    batch = CsvBatch(
220        model,
221        methods,
222        nvot=nvot,
223        ncand=ncand,
224        niter=niter,
225        baseName=baseName,
226        media=media,
227        seed=seed,
228        force=force,
229    )
230    return batch.results
231
232
233def run_simulation_dataframe(*args, **kwargs):
234    """Run a simulation and return its result rows as a pandas DataFrame."""
235    return run_simulation(*args, **kwargs).dataframe
236
237
238__all__ = [
239    "CsvBatch",
240    "allSystems",
241    "baseRuns",
242    "markMethods",
243    "medianRuns",
244    "run_simulation",
245    "run_simulation_dataframe",
246    "uniquify",
247]
248
249# usage example:
250# >>> from vse import *
251# >>> vses = CsvBatch(KSModel(dcdecay=(1,3),wcdecay=(1.5,3), dccut = .2, wcalpha=1.5),
252#           allSystems, nvot=40, ncand=6, niter=15000, baseName="target",
253#           media=fuzzyMediaFor())
254
255if __name__ == "__main__":
256    import doctest
257
258    setDebug(False)
259    doctest.testmod()
class CsvBatch:
 37class CsvBatch:
 38    @autoassign
 39    def __init__(
 40        self,
 41        model,
 42        methods,
 43        nvot,
 44        ncand,
 45        niter,
 46        baseName=None,
 47        media=truth,
 48        seed=None,
 49        force=False,
 50    ):
 51        """A harness function which creates niter elections from model and finds three kinds
 52        of utility for all methods given.
 53
 54        for instance:
 55
 56        >>> csvs = CsvBatch(PolyaModel(), [[Score(), baseRuns], [Mav(), medianRuns]], nvot=5, ncand=4, niter=3)
 57        >>> len(csvs.rows)
 58        60
 59        """
 60        rows = []
 61        emodel = str(model)
 62        if seed is None:
 63            seed = (baseName or "") + str(niter)
 64            self.seed = seed
 65        random.seed(seed)
 66        try:
 67            from git import Repo
 68
 69            repo = Repo(os.getcwd())
 70            if not force:
 71                assert not repo.is_dirty()
 72            self.repo_version = repo.head.commit.hexsha
 73        except Exception:
 74            self.repo_version = "unknown repo version"
 75        for i in range(niter):
 76            eid = uuid4()
 77            electorate = model(nvot, ncand)
 78            for method, chooserFuns in methods:
 79                results = method.resultsTable(
 80                    eid, emodel, ncand, electorate, chooserFuns, media=media
 81                )
 82                rows.extend(results)
 83            debug(i, results[1:3])
 84        self.rows = rows
 85        if baseName:
 86            self.saveFile(baseName)
 87
 88    def saveFile(self, baseName="SimResults"):
 89        """print the result of doVse in an accessible format.
 90        for instance:
 91
 92        csvs.saveFile()
 93        """
 94        i = 1
 95        while os.path.isfile(baseName + str(i) + ".csv"):
 96            i += 1
 97        keys = ["vse", "method", "chooser", *list(self.rows[0].keys())]
 98        for n in range(4):
 99            keys.extend([f"tallyName{str(n)}", f"tallyVal{str(n)}"])
100        keys = uniquify(keys)
101        path = baseName + str(i) + ".csv"
102        with open(path, "w") as myFile:
103            print(
104                f"# {dict(media=self.media.__name__, version=self.repo_version, seed=self.seed, model=self.model, methods=self.methods, nvot=self.nvot, ncand=self.ncand, niter=self.niter)}",
105                file=myFile,
106            )
107
108            dw = csv.DictWriter(myFile, keys, restval="NA")
109            dw.writeheader()
110            for r in self.rows:
111                dw.writerow(r)
112        return path
113
114    @property
115    def results(self):
116        """Return this batch as a pandas-backed ``VseResults`` object."""
117        from .dataframe import VseResults
118
119        return VseResults.from_rows(self.rows)
120
121    @property
122    def dataframe(self):
123        """Return this batch's rows as a pandas DataFrame."""
124        return self.to_dataframe()
125
126    @property
127    def df(self):
128        """Alias for ``dataframe``."""
129        return self.dataframe
130
131    def to_dataframe(self, copy=True):
132        """Return this batch's rows as a pandas DataFrame."""
133        return self.results.to_dataframe(copy=copy)
134
135    def summarize(self, group_by=("method", "chooser"), sort_by="mean_vse", ascending=False):
136        """Return a pandas DataFrame summarizing VSE scores for this batch."""
137        return self.results.summarize(
138            group_by=group_by,
139            sort_by=sort_by,
140            ascending=ascending,
141        )
142
143    def report(self, group_by=("method", "chooser")):
144        """Return common pandas report tables for this batch."""
145        return self.results.report(group_by=group_by)
146
147    def plot_vse(self, *args, **kwargs):
148        """Plot summarized VSE scores for this batch."""
149        return self.results.plot_vse(*args, **kwargs)
@autoassign
CsvBatch( model, methods, nvot, ncand, niter, baseName=None, media=<function truth>, seed=None, force=False)
38    @autoassign
39    def __init__(
40        self,
41        model,
42        methods,
43        nvot,
44        ncand,
45        niter,
46        baseName=None,
47        media=truth,
48        seed=None,
49        force=False,
50    ):
51        """A harness function which creates niter elections from model and finds three kinds
52        of utility for all methods given.
53
54        for instance:
55
56        >>> csvs = CsvBatch(PolyaModel(), [[Score(), baseRuns], [Mav(), medianRuns]], nvot=5, ncand=4, niter=3)
57        >>> len(csvs.rows)
58        60
59        """
60        rows = []
61        emodel = str(model)
62        if seed is None:
63            seed = (baseName or "") + str(niter)
64            self.seed = seed
65        random.seed(seed)
66        try:
67            from git import Repo
68
69            repo = Repo(os.getcwd())
70            if not force:
71                assert not repo.is_dirty()
72            self.repo_version = repo.head.commit.hexsha
73        except Exception:
74            self.repo_version = "unknown repo version"
75        for i in range(niter):
76            eid = uuid4()
77            electorate = model(nvot, ncand)
78            for method, chooserFuns in methods:
79                results = method.resultsTable(
80                    eid, emodel, ncand, electorate, chooserFuns, media=media
81                )
82                rows.extend(results)
83            debug(i, results[1:3])
84        self.rows = rows
85        if baseName:
86            self.saveFile(baseName)

A harness function which creates niter elections from model and finds three kinds of utility for all methods given.

for instance:

>>> csvs = CsvBatch(PolyaModel(), [[Score(), baseRuns], [Mav(), medianRuns]], nvot=5, ncand=4, niter=3)
>>> len(csvs.rows)
60
rows
def saveFile(self, baseName='SimResults'):
 88    def saveFile(self, baseName="SimResults"):
 89        """print the result of doVse in an accessible format.
 90        for instance:
 91
 92        csvs.saveFile()
 93        """
 94        i = 1
 95        while os.path.isfile(baseName + str(i) + ".csv"):
 96            i += 1
 97        keys = ["vse", "method", "chooser", *list(self.rows[0].keys())]
 98        for n in range(4):
 99            keys.extend([f"tallyName{str(n)}", f"tallyVal{str(n)}"])
100        keys = uniquify(keys)
101        path = baseName + str(i) + ".csv"
102        with open(path, "w") as myFile:
103            print(
104                f"# {dict(media=self.media.__name__, version=self.repo_version, seed=self.seed, model=self.model, methods=self.methods, nvot=self.nvot, ncand=self.ncand, niter=self.niter)}",
105                file=myFile,
106            )
107
108            dw = csv.DictWriter(myFile, keys, restval="NA")
109            dw.writeheader()
110            for r in self.rows:
111                dw.writerow(r)
112        return path

print the result of doVse in an accessible format. for instance:

csvs.saveFile()

results
114    @property
115    def results(self):
116        """Return this batch as a pandas-backed ``VseResults`` object."""
117        from .dataframe import VseResults
118
119        return VseResults.from_rows(self.rows)

Return this batch as a pandas-backed VseResults object.

dataframe
121    @property
122    def dataframe(self):
123        """Return this batch's rows as a pandas DataFrame."""
124        return self.to_dataframe()

Return this batch's rows as a pandas DataFrame.

df
126    @property
127    def df(self):
128        """Alias for ``dataframe``."""
129        return self.dataframe

Alias for dataframe.

def to_dataframe(self, copy=True):
131    def to_dataframe(self, copy=True):
132        """Return this batch's rows as a pandas DataFrame."""
133        return self.results.to_dataframe(copy=copy)

Return this batch's rows as a pandas DataFrame.

def summarize( self, group_by=('method', 'chooser'), sort_by='mean_vse', ascending=False):
135    def summarize(self, group_by=("method", "chooser"), sort_by="mean_vse", ascending=False):
136        """Return a pandas DataFrame summarizing VSE scores for this batch."""
137        return self.results.summarize(
138            group_by=group_by,
139            sort_by=sort_by,
140            ascending=ascending,
141        )

Return a pandas DataFrame summarizing VSE scores for this batch.

def report(self, group_by=('method', 'chooser')):
143    def report(self, group_by=("method", "chooser")):
144        """Return common pandas report tables for this batch."""
145        return self.results.report(group_by=group_by)

Return common pandas report tables for this batch.

def plot_vse(self, *args, **kwargs):
147    def plot_vse(self, *args, **kwargs):
148        """Plot summarized VSE scores for this batch."""
149        return self.results.plot_vse(*args, **kwargs)

Plot summarized VSE scores for this batch.

allSystems = [[<vse_sim.Score.<locals>.Score0to object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.Score.<locals>.Score0to object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.Score.<locals>.Score0to object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.Score.<locals>.Score0to object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.BulletyApprovalWith.<locals>.BulletyApproval object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.Srv.<locals>.Srv0to object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.Srv.<locals>.Srv0to object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.Plurality object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.Borda object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.Irv object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.IrvPrime object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.Schulze object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.Rp object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.V321 object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.Mav object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.LazyChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.Mj object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.LazyChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.IRNR object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]]]
baseRuns = [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]
markMethods = [[<vse_sim.Srv.<locals>.Srv0to object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.Srv.<locals>.Srv0to object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.Srv.<locals>.Srv0to object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.Srv.<locals>.Srv0to object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.Srv.<locals>.Srv0to object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.Srv.<locals>.Srv0to object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.Srv.<locals>.Srv0to object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.Srv.<locals>.Srv0to object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.Score.<locals>.Score0to object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.V321 object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.BulletyApprovalWith.<locals>.BulletyApproval object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.Irv object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]], [<vse_sim.Plurality object>, [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>]]]
medianRuns = [<vse_sim.OssChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.ProbChooser object>, <vse_sim.LazyChooser object>, <vse_sim.ProbChooser object>]
def run_simulation( model, methods, nvot, ncand, niter, baseName=None, media=<function truth>, seed=None, force=False):
208def run_simulation(
209    model,
210    methods,
211    nvot,
212    ncand,
213    niter,
214    baseName=None,
215    media=truth,
216    seed=None,
217    force=False,
218):
219    """Run a simulation and return a pandas-backed ``VseResults`` object."""
220    batch = CsvBatch(
221        model,
222        methods,
223        nvot=nvot,
224        ncand=ncand,
225        niter=niter,
226        baseName=baseName,
227        media=media,
228        seed=seed,
229        force=force,
230    )
231    return batch.results

Run a simulation and return a pandas-backed VseResults object.

def run_simulation_dataframe(*args, **kwargs):
234def run_simulation_dataframe(*args, **kwargs):
235    """Run a simulation and return its result rows as a pandas DataFrame."""
236    return run_simulation(*args, **kwargs).dataframe

Run a simulation and return its result rows as a pandas DataFrame.

def uniquify(seq):
28def uniquify(seq):
29    # order preserving
30    checked = []
31    for e in seq:
32        if e not in checked:
33            checked.append(e)
34    return checked