Loading...

Features Engineering

While preparing our data, we need to think constantly about the most suitable features we can use to achieve our overall goals.

Features engineering makes use of many techniques - too many to go over in this short lesson. We’ll focus on the most popular ones.

Customized Features Engineering

To build a customized feature, you can use the eval() method of the vDataFrame. Let’s look at an example with the well-known titanic dataset.

import verticapy as vp
from verticapy.datasets import load_titanic

titanic = load_titanic()
titanic.head(100)
123
pclass
Int
100%
...
123
body
Int
9%
Abc
Varchar(100)
57%
11...22
21...[null]
31...[null]
41...[null]
51...[null]
61...[null]
71...[null]
81...62
91...[null]
101...[null]
111...[null]
121...[null]
131...110
141...[null]
151...[null]
161...38
171...[null]
181...126
191...292
201...175
211...[null]
221...122
231...166
241...[null]
251...207
261...[null]
271...232
281...[null]
291...[null]
301...[null]
311...[null]
321...[null]
331...46
341...169
351...[null]
361...[null]
371...[null]
381...[null]
391...[null]
401...[null]
411...[null]
421...[null]
431...[null]
441...[null]
451...[null]
461...[null]
471...[null]
481...[null]
491...[null]
501...[null]
511...[null]
521...[null]
531...[null]
541...[null]
551...[null]
561...[null]
571...[null]
581...[null]
591...[null]
601...[null]
611...[null]
621...[null]
631...[null]
641...[null]
651...[null]
661...[null]
671...[null]
681...[null]
691...[null]
701...[null]
711...[null]
721...[null]
731...[null]
742...[null]
752...[null]
762...[null]
772...[null]
782...[null]
792...[null]
802...[null]
812...[null]
822...[null]
832...236
842...[null]
852...[null]
862...[null]
872...155
882...[null]
892...75
902...35
912...[null]
922...[null]
932...[null]
942...[null]
952...[null]
962...[null]
972...[null]
982...165
992...[null]
1002...[null]

The feature parch corresponds to the number of parents and children on-board. The feature sibsp corresponds to the number of siblings and spouses on-board. We can create the feature family_size which is equal to parch + sibsp + 1.

titanic["family_size"] = titanic["parch"] + titanic["sibsp"] + 1
titanic.select(["parch", "sibsp", "family_size"])
123
parch
Integer
100%
...
123
sibsp
Integer
100%
123
family_size
Integer
100%
10...01
20...01
30...01
40...01
50...12
61...13
70...12
80...12
90...01
100...12
110...01
120...12
130...01
140...01
150...01
160...12
170...01
180...01
190...01
200...01

When using the eval() method, you can enter any SQL expression and VerticaPy will evaluate it!

Regular Expressions

To compute features using regular expressions, we’ll use the regexp() method.

help(vp.vDataFrame.regexp)
Help on function regexp in module verticapy.core.vdataframe._text:

regexp(self, column: str, pattern: str, method: Literal['count', 'ilike', 'instr', 'like', 'not_ilike', 'not_like', 'replace', 'substr'] = 'substr', position: int = 1, occurrence: int = 1, replacement: Optional[str] = None, return_position: int = 0, name: Optional[str] = None) -> 'vDataFrame'

Computes a new vDataColumn based on regular expressions.

Parameters
----------
column: str
    Input vDataColumn  used  to compute the  regular
    expression.
pattern: str
    The regular expression.
method: str, optional
    Method used to compute the regular  expressions.

         - count:
            Returns the number of times a
            regular expression matches each
            element of the input vDataColumn.
         - ilike:
            Returns  True if  the  vDataColumn
            element  contains a match for  the
            regular expression.
         - instr:
            Returns  the  starting  or  ending
            position in  a vDataColumn element
            where a regular expression matches.
         - like:
            Returns  True  if the  vDataColumn
            element    matches   the   regular
            expression.
         - not_ilike :
            Returns  True  if the  vDataColumn
            element  does  not match the  case
            -insensitive  regular   expression.
         - not_like:
            Returns  True if  the  vDataColumn
            element  does not contain a  match
            for the regular expression.
         - replace:
            Replaces   all  occurrences  of  a
            substring  that  match  a  regular
            expression  with another substring.
         - substr:
            Returns the substring that matches
            a  regular   expression  within  a
            vDataColumn.

position: int, optional
    The number of characters from the start of the string
    where the function should start searching for matches.
occurrence: int, optional
    Controls  which occurrence of a pattern match in  the
    string to return.
replacement: str, optional
    The string to replace matched substrings.
return_position: int, optional
    Sets the position within the string to return.
name: str, optional
    New feature name. If empty, a name is generated.

Returns
-------
vDataFrame
    self

Consider the following example: notice that passenger names include their title.

titanic["name"]
Abc
name
Varchar(164)
1Artagaveytia, Mr. Ramon
2Blackwell, Mr. Stephen Weart
3Cairns, Mr. Alexander
4Carrau, Mr. Jose Pedro
5Clark, Mr. Walter Miller
6Compton, Mr. Alexander Taylor Jr
7Davidson, Mr. Thornton
8Douglas, Mr. Walter Donald
9Evans, Miss. Edith Corse
10Futrelle, Mr. Jacques Heath
11Giglio, Mr. Victor
12Harris, Mr. Henry Birkhardt
13Harrison, Mr. William
14Head, Mr. Christopher
15Hilliard, Mr. Herbert Henry
16Holverson, Mr. Alexander Oskar
17Hoyt, Mr. William Fisher
18Long, Mr. Milton Clyde
19McCaffry, Mr. Thomas Francis
20McCarthy, Mr. Timothy J

Let’s extract the title using regular expressions.

titanic.regexp(
    column = "name",
    name = "title",
    pattern = " ([A-Za-z])+\.",
    method = "substr",
)
titanic.select(["name", "title"])
Abc
name
Varchar(164)
100%
Abc
title
Varchar(164)
100%
1Artagaveytia, Mr. Ramon Mr.
2Blackwell, Mr. Stephen Weart Mr.
3Cairns, Mr. Alexander Mr.
4Carrau, Mr. Jose Pedro Mr.
5Clark, Mr. Walter Miller Mr.
6Compton, Mr. Alexander Taylor Jr Mr.
7Davidson, Mr. Thornton Mr.
8Douglas, Mr. Walter Donald Mr.
9Evans, Miss. Edith Corse Miss.
10Futrelle, Mr. Jacques Heath Mr.
11Giglio, Mr. Victor Mr.
12Harris, Mr. Henry Birkhardt Mr.
13Harrison, Mr. William Mr.
14Head, Mr. Christopher Mr.
15Hilliard, Mr. Herbert Henry Mr.
16Holverson, Mr. Alexander Oskar Mr.
17Hoyt, Mr. William Fisher Mr.
18Long, Mr. Milton Clyde Mr.
19McCaffry, Mr. Thomas Francis Mr.
20McCarthy, Mr. Timothy J Mr.

Advanced Analytical Functions

The analytic() method contains the many advanced analytical functions in VerticaPy.

help(vp.vDataFrame.analytic)
Help on function analytic in module verticapy.core.vdataframe._math:

analytic(self, func: str, columns: Optional[Annotated[Union[str, list[str]], 'STRING representing one column or a list of columns']] = None, by: Optional[Annotated[Union[str, list[str]], 'STRING representing one column or a list of columns']] = None, order_by: Union[NoneType, Annotated[Union[str, list[str]], 'STRING representing one column or a list of columns'], dict] = None, name: Optional[str] = None, offset: int = 1, x_smoothing: float = 0.5, add_count: bool = True) -> 'vDataFrame'

Adds a new vDataColumn to the vDataFrame by using an advanced
analytical function on one or two specific vDataColumns.

.. warning::

    Some analytical  functions can make the vDataFrame
    structure  more resource intensive. It is best  to
    check  the structure of  the vDataFrame with  the
    ``current_relation`` method and save it with the
    ``to_db``  method,  uisng  the  parameters
    ``inplace = True`` and ``relation_type = table``.

Parameters
----------
func: str
    Function to apply.

    - aad:
        average absolute deviation
    - beta:
        Beta Coefficient between 2 vDataColumns
    - count:
        number of non-missing elements
    - corr:
        Pearson's correlation between 2 vDataColumns
    - cov:
        covariance between 2 vDataColumns
    - dense_rank:
        dense rank
    - ema:
        exponential moving average
    - first_value:
        first non null lead
    - iqr:
        interquartile range
    - kurtosis:
        kurtosis
    - jb:
        Jarque-Bera index
    - lead:
        next element
    - lag:
        previous element
    - last_value:
        first non null lag
    - mad:
        median absolute deviation
    - max:
        maximum
    - mean:
        average
    - median :
        median
    - min:
        minimum
    - mode:
        most occurent element
    - q%:
        q quantile (ex: 50% for the median)
    - pct_change:
        ratio between the current value and the previous one
    - percent_rank :
        percent rank
    - prod:
        product
    - range:
        difference between the max and the min
    - rank:
        rank
    - row_number:
        row number
    - sem:
        standard error of the mean
    - skewness:
        skewness
    - sum:
        sum
    - std:
        standard deviation
    - unique:
        cardinality (count distinct)
    - var:
        variance

    Other analytical functions could work if they are part of your DB
    version.
columns: SQLColumns, optional
    Input vDataColumns. Must be a list of one or two elements.
by: SQLColumns, optional
    vDataColumns used in the partition.
order_by: dict / list, optional
    Either a list of the vDataColumns used to sort (in ascending order)
    the data, or a dictionary of vDataColumns and their sorting
    methods. For example, to sort by "column1" ASC and "column2" DESC,
    write: ``{"column1": "asc", "column2": "desc"}``
name: str, optional
    Name of  the new vDataColumn. If empty, a default name based on the
    other parameters is generated.
offset: int, optional
    Lead/Lag  offset  if parameter ``func`` is the function  'lead'/'lag'.
x_smoothing: float, optional
    The  smoothing parameter of the 'ema' if the  function is 'ema'. It
    must be a float in the range [0;1].
add_count: bool, optional
    If the ``func`` is set to ``mode`` and this parameter is True, a column
    with the mode number of occurences is added to the vDataFrame.

Returns
-------
vDataFrame
    self

To demonstrate some of these techniques, let’s use the amazon dataset and perform some computations.

from verticapy.datasets import load_amazon

amazon = load_amazon()
amazon.head(100)
📅
date
Date
100%
...
Abc
state
Varchar(32)
100%
123
number
Int
100%
11998-01-01...AMAPÁ0
21998-01-01...AMAZONAS0
31998-01-01...DISTRITO FEDERAL0
41998-01-01...ESPÍRITO SANTO0
51998-01-01...MARANHÃO0
61998-01-01...PARANÁ0
71998-01-01...PIAUÍ0
81998-01-01...RORAIMA0
91998-01-01...SERGIPE0
101998-01-01...SÃO PAULO0
111998-02-01...GOIÁS0
121998-02-01...MATO GROSSO DO SUL0
131998-02-01...MINAS GERAIS0
141998-02-01...PARAÍBA0
151998-02-01...SANTA CATARINA0
161998-02-01...SÃO PAULO0
171998-03-01...AMAPÁ0
181998-03-01...BAHIA0
191998-03-01...MATO GROSSO DO SUL0
201998-03-01...PARÁ0
211998-03-01...PERNAMBUCO0
221998-03-01...RIO GRANDE DO SUL0
231998-04-01...CEARÁ0
241998-04-01...PARANÁ0
251998-04-01...PARAÍBA0
261998-04-01...PARÁ0
271998-05-01...ALAGOAS0
281998-05-01...AMAPÁ0
291998-05-01...MARANHÃO0
301998-05-01...MATO GROSSO DO SUL0
311998-05-01...RIO GRANDE DO SUL0
321998-05-01...TOCANTINS0
331998-06-01...ESPÍRITO SANTO6
341998-06-01...RIO DE JANEIRO3
351998-06-01...RIO GRANDE DO NORTE1
361998-06-01...SÃO PAULO451
371998-07-01...ESPÍRITO SANTO37
381998-07-01...MARANHÃO274
391998-07-01...MATO GROSSO360
401998-07-01...MATO GROSSO DO SUL3712
411998-07-01...PARAÍBA0
421998-07-01...PARÁ638
431998-07-01...RONDÔNIA365
441998-07-01...SÃO PAULO596
451998-08-01...ALAGOAS1
461998-08-01...BAHIA815
471998-08-01...DISTRITO FEDERAL48
481998-08-01...ESPÍRITO SANTO38
491998-08-01...MARANHÃO1176
501998-08-01...MATO GROSSO228
511998-08-01...MINAS GERAIS875
521998-08-01...PIAUÍ711
531998-08-01...RIO GRANDE DO SUL9
541998-08-01...RORAIMA0
551998-08-01...SERGIPE0
561998-09-01...AMAPÁ20
571998-09-01...DISTRITO FEDERAL33
581998-09-01...PIAUÍ1991
591998-09-01...RORAIMA2
601998-10-01...AMAZONAS83
611998-10-01...GOIÁS1034
621998-10-01...MATO GROSSO576
631998-10-01...PARAÍBA179
641998-10-01...PARÁ3665
651998-10-01...PIAUÍ2586
661998-10-01...SERGIPE0
671998-11-01...ALAGOAS19
681998-11-01...AMAPÁ131
691998-11-01...CEARÁ575
701998-11-01...DISTRITO FEDERAL0
711998-11-01...MARANHÃO2237
721998-11-01...RIO DE JANEIRO6
731998-11-01...RIO GRANDE DO SUL28
741998-11-01...SÃO PAULO488
751998-12-01...BAHIA82
761998-12-01...MARANHÃO1399
771998-12-01...MATO GROSSO100
781998-12-01...PARAÍBA51
791998-12-01...PERNAMBUCO59
801998-12-01...RIO DE JANEIRO1
811998-12-01...RONDÔNIA33
821998-12-01...TOCANTINS9
831999-01-01...ALAGOAS58
841999-01-01...GOIÁS14
851999-01-01...MATO GROSSO239
861999-01-01...MINAS GERAIS36
871999-01-01...PARÁ87
881999-01-01...PERNAMBUCO102
891999-01-01...RONDÔNIA1
901999-01-01...SÃO PAULO7
911999-01-01...TOCANTINS36
921999-02-01...ACRE0
931999-02-01...CEARÁ16
941999-02-01...MATO GROSSO69
951999-02-01...MATO GROSSO DO SUL28
961999-02-01...PERNAMBUCO13
971999-02-01...RONDÔNIA1
981999-02-01...SANTA CATARINA2
991999-02-01...TOCANTINS1
1001999-03-01...AMAPÁ2

For each state, let’s compute the previous number of forest fires.

amazon.analytic(
    name = "previous_number",
    func = "lag",
    columns = "number",
    by = "state",
    order_by = {"date": "asc"},
)
📅
date
Date
100%
...
Abc
state
Varchar(32)
100%
123
previous_number
Integer
99%
11998-01-01...TOCANTINS[null]
21998-02-01...TOCANTINS0
31998-03-01...TOCANTINS0
41998-04-01...TOCANTINS0
51998-05-01...TOCANTINS0
61998-06-01...TOCANTINS0
71998-07-01...TOCANTINS252
81998-08-01...TOCANTINS640
91998-09-01...TOCANTINS3747
101998-10-01...TOCANTINS5149
111998-11-01...TOCANTINS1738
121998-12-01...TOCANTINS1
131999-01-01...TOCANTINS9
141999-02-01...TOCANTINS36
151999-03-01...TOCANTINS1
161999-04-01...TOCANTINS1
171999-05-01...TOCANTINS9
181999-06-01...TOCANTINS24
191999-07-01...TOCANTINS113
201999-08-01...TOCANTINS373

Moving Windows

Moving windows are powerful features. Moving windows are managed by the rolling() method in VerticaPy.

help(vp.vDataFrame.rolling)
Help on function rolling in module verticapy.core.vdataframe._rolling:

rolling(self, func: str, window: Union[list, tuple], columns: Annotated[Union[str, list[str]], 'STRING representing one column or a list of columns'], by: Optional[Annotated[Union[str, list[str]], 'STRING representing one column or a list of columns']] = None, order_by: Union[NoneType, dict, list] = None, name: Optional[str] = None) -> 'vDataFrame'

Adds a new :py:class:`~vDataColumn` to the
:py:class:`~vDataFrame` by using an advanced
analytical  window function on one or two
specific :py:class:`~vDataColumn`.

.. warning::

    Some window functions can make the
    vDataFrame structure heavier. It is
    recommended to always check the current
    structure with the ``current_relation``
    method and to save it with the ``to_db``
    method, using the parameters ``inplace
    = True`` and ``relation_type = table``.

.. warning::

    Make use of the ``order_by`` parameter to sort
    your data. Otherwise, you might encounter unexpected
    results, as Vertica does not work with indexes, and
    the data may be randomly shuffled.

Parameters
----------
func: str
    Function to use.

    - aad:
        average absolute deviation
    - beta:
        Beta Coefficient between 2 vDataColumns
    - count:
        number of non-missing elements
    - corr:
        Pearson correlation between 2 vDataColumns
    - cov:
        covariance between 2 vDataColumns
    - kurtosis:
        kurtosis
    - jb:
        Jarque-Bera index
    - max:
        maximum
    - mean:
        average
    - min:
        minimum
    - prod:
        product
    - range:
        difference between the max and the min
    - sem:
        standard error of the mean
    - skewness:
        skewness
    - sum:
        sum
    - std:
        standard deviation
    - var:
        variance

    Other window functions could work if it is part of
    the DB version you are using.

window: list | tuple
    Window Frame Range.
    If set to two integers, computes a Row Window, otherwise
    it computes a Time  Window. For example, if set  to
    ``(-5, 1)``,  the moving  windows will take 5 rows  preceding
    and one following. If set to ``('- 5 minutes', '0 minutes')``,
    the  moving window  will take all elements of the last  5
    minutes.
columns: SQLColumns
    Input :py:class:`~vDataColumn`. Must be a list of one
    or two elements.
by: SQLColumns, optional
    vDataColumns used in the partition.
order_by: dict | list, optional
    List of the vDataColumns used to sort the data using
    ascending/descending order or a dictionary of all the
    sorting methods.
    For example, to sort by "column1" ASC and "column2" DESC,
    use: ``{"column1": "asc", "column2": "desc"}``.
name: str, optional
    Name of the new :py:class:`~vDataColumn`. If empty, a
    default name is generated.

Returns
-------
vDataFrame
    self

Let’s look at forest fires for each state three months preceding two months following the examined period.

amazon.rolling(
    name = "number_3mp_2mf",
    func = "sum",
    window = ("- 3 months", "2 months"),
    columns = "number",
    by = "state",
    order_by = {"date": "asc"},
)
📅
date
Date
100%
...
123
previous_number
Integer
99%
123
number_3mp_2mf
Integer
100%
11998-01-01...[null]0
21998-02-01...00
31998-03-01...00
41998-04-01...00
51998-05-01...046
61998-06-01...0235
71998-07-01...46946
81998-08-01...1892937
91998-09-01...7115477
101998-10-01...19915712
111998-11-01...25865120
121998-12-01...4243150
131999-01-01...119590
141999-02-01...21176
151999-03-01...22176
161999-04-01...465
171999-05-01...1091
181999-06-01...8188
191999-07-01...47677
201999-08-01...1231541

Moving windows give us infinite possibilities for creating new features.

After we’ve finished preparing our data, our next task is to create a machine learning model.