h2o-py/h2o/model/model_base.py
def partial_plot(self, data, cols, destination_key=None, nbins=20, weight_column=None,
                     plot=True, plot_stddev = True, figsize=(7, 10), server=False, include_na=False, user_splits=None,
                     save_to_file=None):
        """
        Create partial dependence plot which gives a graphical depiction of the marginal effect of a variable on the
        response. The effect of a variable is measured in change in the mean response.

        :param H2OFrame data: An H2OFrame object used for scoring and constructing the plot.
        :param cols: Feature(s) for which partial dependence will be calculated.
        :param destination_key: An key reference to the created partial dependence tables in H2O.
        :param nbins: Number of bins used. For categorical columns make sure the number of bins exceed the level count. If you enable add_missing_NA, the returned length will be nbin+1.
        :param weight_column: A string denoting which column of data should be used as the weight column.
        :param plot: A boolean specifying whether to plot partial dependence table.
        :param plot_stddev: A boolean specifying whether to add std err to partial dependence plot.
        :param figsize: Dimension/size of the returning plots, adjust to fit your output cells.
        :param server: ?
        :param include_na: A boolean specifying whether missing value should be included in the Feature values.
        :param user_splits: a dictionary containing column names as key and user defined split values as value in a list.
        :param save_to_file Fully qualified name to an image file the resulting plot should be saved to, e.g. '/home/user/pdpplot.png'. The 'png' postfix might be omitted. If the file already exists, it will be overridden. Plot is only saved if plot = True.
        :returns: Plot and list of calculated mean response tables for each feature requested.
        """

        if not isinstance(data, h2o.H2OFrame): raise ValueError("data must be an instance of H2OFrame")
        assert_is_type(cols, [str])
        assert_is_type(destination_key, None, str)
        assert_is_type(nbins, int)
        assert_is_type(plot, bool)
        assert_is_type(figsize, (int, int))

        # Check cols specified exist in frame data
        for xi in cols:
            if xi not in data.names:
                raise H2OValueError("Column %s does not exist in the training frame" % xi)
        if isinstance(weight_column, int) and not (weight_column == -1):
            raise H2OValueError("Weight column should be a column name in your data frame.")
        elif isinstance(weight_column, str): # index is a name
            if weight_column not in data.names:
                raise H2OValueError("Column %s does not exist in the data frame" % weight_column)
            weight_column = data.names.index(weight_column)

        kwargs = {}
        kwargs["cols"] = cols
        kwargs["model_id"] = self.model_id
        kwargs["frame_id"] = data.frame_id
        kwargs["nbins"] = nbins
        kwargs["destination_key"] = destination_key
        kwargs["weight_column_index"] = weight_column
        kwargs["add_missing_na"] = include_na

        # extract user defined split points from dict user_splits into an integer array of column indices
        # and a double array of user define values for the corresponding columns
        if not(user_splits == None):
            if not(isinstance(user_splits, dict)):
                raise H2OValueError("user_splits must be a Python dict.")
            else:
                if len(user_splits)>0: # do nothing with an empty dict
                    user_cols = []
                    user_values = []
                    user_num_splits = []
                    data_ncol = data.ncol
                    column_names = data.names
                    for colKey,val in user_splits.items():
                        if is_type(colKey, str) and colKey in column_names:
                            user_cols.append(colKey)
                        elif isinstance(colKey, int) and colKey < data_ncol:
                            user_cols.append(column_names[colKey])
                        else:
                            raise H2OValueError("column names/indices used in user_splits are not valid.  They "
                                                "should be chosen from the columns of your data set.")

                        if data[colKey].isfactor()[0] or data[colKey].isnumeric()[0]: # replace enum string with actual value
                            nVal = len(val)
                            if data[colKey].isfactor()[0]:
                                domains = data[colKey].levels()[0]

                                numVal = [0]*nVal
                                for ind in range(nVal):
                                    if (val[ind] in domains):
                                        numVal[ind] = domains.index(val[ind])
                                    else:
                                        raise H2OValueError("Illegal enum value {0} encountered.  To include missing"
                                                        " values in your feature values, set include_na to "
                                                        "True".format(val[ind]))

                                user_values.extend(numVal)
                            else:
                                user_values.extend(val)
                            user_num_splits.append(nVal)
                        else:
                            raise H2OValueError("Partial dependency plots are generated for numerical and categorical "
                                                "columns only.")
                    kwargs["user_cols"] = user_cols
                    kwargs["user_splits"] = user_values
                    kwargs["num_user_splits"] = user_num_splits
                else:
                    kwargs["user_cols"] = None
                    kwargs["user_splits"] = None
                    kwargs["num_user_splits"] = None

        json = H2OJob(h2o.api("POST /3/PartialDependence/", data=kwargs),  job_type="PartialDependencePlot").poll()
        json = h2o.api("GET /3/PartialDependence/%s" % json.dest_key)

        # Extract partial dependence data from json response
        pps = json["partial_dependence_data"]

        # Plot partial dependence plots using matplotlib
        if plot:
            plt = _get_matplotlib_pyplot(server)
            if not plt: return

            fig, axs = plt.subplots(len(cols), squeeze=False, figsize=figsize)
            for i, pp in enumerate(pps):
                # Check weather column was categorical or numeric
                col = cols[i]
                cat = data[col].isfactor()[0]
                upper = [a + b for a, b in zip(pp[1], pp[2]) ]
                lower = [a - b for a, b in zip(pp[1], pp[2]) ]
                if cat:
                    labels = pp[0]
                    x = range(len(labels))
                    y = pp[1]
                    axs[i, 0].plot(x, y, "ro")
                    if plot_stddev:
                        axs[i, 0].plot(x, lower, 'b--')
                        axs[i, 0].plot(x, upper, 'b--')
                    axs[i, 0].set_ylim(min(lower) - 0.1*abs(min(lower)), max(upper) + 0.1*abs(max(upper)))
                    axs[i, 0].set_xticks(x)
                    axs[i, 0].set_xticklabels(labels)
                    axs[i, 0].margins(0.2)
                else:
                    x = pp[0]
                    y = pp[1]
                    axs[i, 0].plot(x, y, "r-")
                    if plot_stddev:
                        axs[i, 0].plot(x, lower, 'b--')
                        axs[i, 0].plot(x, upper, 'b--')
                    axs[i, 0].set_xlim(min(x), max(x))
                    axs[i, 0].set_ylim(min(lower) - 0.1*abs(min(lower)), max(upper) + 0.1*abs(max(upper)))

                axs[i, 0].set_title("Partial Dependence Plot For {}".format(col))
                axs[i, 0].set_xlabel(pp.col_header[0])
                axs[i, 0].set_ylabel(pp.col_header[1])
                axs[i, 0].xaxis.grid()
                axs[i, 0].yaxis.grid()
            if len(col) > 1:
                fig.tight_layout(pad=0.4, w_pad=0.5, h_pad=1.0)
            if(save_to_file is not None):
                plt.savefig(save_to_file)

        return pps
def partial_plot(self, data, cols, destination_key=None, nbins=20, weight_column=None,
                     plot=True, plot_stddev = True, figsize=(7, 10), server=False, include_na=False, user_splits=None,
                     save_to_file=None):
        """
        Create partial dependence plot which gives a graphical depiction of the marginal effect of a variable on the
        response. The effect of a variable is measured in change in the mean response.

        :param H2OFrame data: An H2OFrame object used for scoring and constructing the plot.
        :param cols: Feature(s) for which partial dependence will be calculated.
        :param destination_key: An key reference to the created partial dependence tables in H2O.
        :param nbins: Number of bins used. For categorical columns make sure the number of bins exceed the level count. If you enable add_missing_NA, the returned length will be nbin+1.
        :param weight_column: A string denoting which column of data should be used as the weight column.
        :param plot: A boolean specifying whether to plot partial dependence table.
        :param plot_stddev: A boolean specifying whether to add std err to partial dependence plot.
        :param figsize: Dimension/size of the returning plots, adjust to fit your output cells.
        :param server: ?
        :param include_na: A boolean specifying whether missing value should be included in the Feature values.
        :param user_splits: a dictionary containing column names as key and user defined split values as value in a list.
        :param save_to_file Fully qualified name to an image file the resulting plot should be saved to, e.g. '/home/user/pdpplot.png'. The 'png' postfix might be omitted. If the file already exists, it will be overridden. Plot is only saved if plot = True.
        :returns: Plot and list of calculated mean response tables for each feature requested.
        """

        if not isinstance(data, h2o.H2OFrame): raise ValueError("data must be an instance of H2OFrame")
        assert_is_type(cols, [str])
        assert_is_type(destination_key, None, str)
        assert_is_type(nbins, int)
        assert_is_type(plot, bool)
        assert_is_type(figsize, (int, int))

        # Check cols specified exist in frame data
        for xi in cols:
            if xi not in data.names:
                raise H2OValueError("Column %s does not exist in the training frame" % xi)
        if isinstance(weight_column, int) and not (weight_column == -1):
            raise H2OValueError("Weight column should be a column name in your data frame.")
        elif isinstance(weight_column, str): # index is a name
            if weight_column not in data.names:
                raise H2OValueError("Column %s does not exist in the data frame" % weight_column)
            weight_column = data.names.index(weight_column)

        kwargs = {}
        kwargs["cols"] = cols
        kwargs["model_id"] = self.model_id
        kwargs["frame_id"] = data.frame_id
        kwargs["nbins"] = nbins
        kwargs["destination_key"] = destination_key
        kwargs["weight_column_index"] = weight_column
        kwargs["add_missing_na"] = include_na

        # extract user defined split points from dict user_splits into an integer array of column indices
        # and a double array of user define values for the corresponding columns
        if not(user_splits == None):
            if not(isinstance(user_splits, dict)):
                raise H2OValueError("user_splits must be a Python dict.")
            else:
                if len(user_splits)>0: # do nothing with an empty dict
                    user_cols = []
                    user_values = []
                    user_num_splits = []
                    data_ncol = data.ncol
                    column_names = data.names
                    for colKey,val in user_splits.items():
                        if is_type(colKey, str) and colKey in column_names:
                            user_cols.append(colKey)
                        elif isinstance(colKey, int) and colKey < data_ncol:
                            user_cols.append(column_names[colKey])
                        else:
                            raise H2OValueError("column names/indices used in user_splits are not valid.  They "
                                                "should be chosen from the columns of your data set.")

                        if data[colKey].isfactor()[0] or data[colKey].isnumeric()[0]: # replace enum string with actual value
                            nVal = len(val)
                            if data[colKey].isfactor()[0]:
                                domains = data[colKey].levels()[0]

                                numVal = [0]*nVal
                                for ind in range(nVal):
                                    if (val[ind] in domains):
                                        numVal[ind] = domains.index(val[ind])
                                    else:
                                        raise H2OValueError("Illegal enum value {0} encountered.  To include missing"
                                                        " values in your feature values, set include_na to "
                                                        "True".format(val[ind]))

                                user_values.extend(numVal)
                            else:
                                user_values.extend(val)
                            user_num_splits.append(nVal)
                        else:
                            raise H2OValueError("Partial dependency plots are generated for numerical and categorical "
                                                "columns only.")
                    kwargs["user_cols"] = user_cols
                    kwargs["user_splits"] = user_values
                    kwargs["num_user_splits"] = user_num_splits
                else:
                    kwargs["user_cols"] = None
                    kwargs["user_splits"] = None
                    kwargs["num_user_splits"] = None

        json = H2OJob(h2o.api("POST /3/PartialDependence/", data=kwargs),  job_type="PartialDependencePlot").poll()
        json = h2o.api("GET /3/PartialDependence/%s" % json.dest_key)

        # Extract partial dependence data from json response
        pps = json["partial_dependence_data"]

        # Plot partial dependence plots using matplotlib
        if plot:
            plt = _get_matplotlib_pyplot(server)
            if not plt: return

            fig, axs = plt.subplots(len(cols), squeeze=False, figsize=figsize)
            for i, pp in enumerate(pps):
                # Check weather column was categorical or numeric
                col = cols[i]
                cat = data[col].isfactor()[0]
                upper = [a + b for a, b in zip(pp[1], pp[2]) ]
                lower = [a - b for a, b in zip(pp[1], pp[2]) ]
                if cat:
                    labels = pp[0]
                    x = range(len(labels))
                    y = pp[1]
                    axs[i, 0].plot(x, y, "ro")
                    if plot_stddev:
                        axs[i, 0].plot(x, lower, 'b--')
                        axs[i, 0].plot(x, upper, 'b--')
                    axs[i, 0].set_ylim(min(lower) - 0.1*abs(min(lower)), max(upper) + 0.1*abs(max(upper)))
                    axs[i, 0].set_xticks(x)
                    axs[i, 0].set_xticklabels(labels)
                    axs[i, 0].margins(0.2)
                else:
                    x = pp[0]
                    y = pp[1]
                    axs[i, 0].plot(x, y, "r-")
                    if plot_stddev:
                        axs[i, 0].plot(x, lower, 'b--')
                        axs[i, 0].plot(x, upper, 'b--')
                    axs[i, 0].set_xlim(min(x), max(x))
                    axs[i, 0].set_ylim(min(lower) - 0.1*abs(min(lower)), max(upper) + 0.1*abs(max(upper)))

                axs[i, 0].set_title("Partial Dependence Plot For {}".format(col))
                axs[i, 0].set_xlabel(pp.col_header[0])
                axs[i, 0].set_ylabel(pp.col_header[1])
                axs[i, 0].xaxis.grid()
                axs[i, 0].yaxis.grid()
            if len(col) > 1:
                fig.tight_layout(pad=0.4, w_pad=0.5, h_pad=1.0)
            if(save_to_file is not None):
                plt.savefig(save_to_file)

        return pps
Create partial dependence plot which gives a graphical depiction of the marginal effect of a variable on the
        response. The effect of a variable is measured in change in the mean response.

        :param H2OFrame data: An H2OFrame object used for scoring and constructing the plot.
        :param cols: Feature(s) for which partial dependence will be calculated.
        :param destination_key: An key reference to the created partial dependence tables in H2O.
        :param nbins: Number of bins used. For categorical columns make sure the number of bins exceed the level count. If you enable add_missing_NA, the returned length will be nbin+1.
        :param weight_column: A string denoting which column of data should be used as the weight column.
        :param plot: A boolean specifying whether to plot partial dependence table.
        :param plot_stddev: A boolean specifying whether to add std err to partial dependence plot.
        :param figsize: Dimension/size of the returning plots, adjust to fit your output cells.
        :param server: ?
        :param include_na: A boolean specifying whether missing value should be included in the Feature values.
        :param user_splits: a dictionary containing column names as key and user defined split values as value in a list.
        :param save_to_file Fully qualified name to an image file the resulting plot should be saved to, e.g. '/home/user/pdpplot.png'. The 'png' postfix might be omitted. If the file already exists, it will be overridden. Plot is only saved if plot = True.
        :returns: Plot and list of calculated mean response tables for each feature requested.