def create_frame(frame_id=None, rows=10000, cols=10, randomize=True,
                 real_fraction=None, categorical_fraction=None, integer_fraction=None,
                 binary_fraction=None, time_fraction=None, string_fraction=None,
                 value=0, real_range=100, factors=100, integer_range=100,
                 binary_ones_fraction=0.02, missing_fraction=0.01,
                 has_response=False, response_factors=2, positive_response=False,
                 seed=None, seed_for_column_types=None):
    """
    Create a new frame with random data.

    Creates a data frame in H2O with real-valued, categorical, integer, and binary columns specified by the user.

    :param frame_id: the destination key. If empty, this will be auto-generated.
    :param rows: the number of rows of data to generate.
    :param cols: the number of columns of data to generate. Excludes the response column if has_response is True.
    :param randomize: If True, data values will be randomly generated. This must be True if either
        categorical_fraction or integer_fraction is non-zero.
    :param value: if randomize is False, then all real-valued entries will be set to this value.
    :param real_range: the range of randomly generated real values.
    :param real_fraction: the fraction of columns that are real-valued.
    :param categorical_fraction: the fraction of total columns that are categorical.
    :param factors: the number of (unique) factor levels in each categorical column.
    :param integer_fraction: the fraction of total columns that are integer-valued.
    :param integer_range: the range of randomly generated integer values.
    :param binary_fraction: the fraction of total columns that are binary-valued.
    :param binary_ones_fraction: the fraction of values in a binary column that are set to 1.
    :param time_fraction: the fraction of randomly created date/time columns.
    :param string_fraction: the fraction of randomly created string columns.
    :param missing_fraction: the fraction of total entries in the data frame that are set to NA.
    :param has_response: A logical value indicating whether an additional response column should be prepended to the
        final H2O data frame. If set to True, the total number of columns will be ``cols + 1``.
    :param response_factors: if has_response is True, then this variable controls the type of the "response" column:
        setting response_factors to 1 will generate real-valued response, any value greater or equal than 2 will
        create categorical response with that many categories.
    :param positive_reponse: when response variable is present and of real type, this will control whether it
        contains positive values only, or both positive and negative.
    :param seed: a seed used to generate random values when ``randomize`` is True.
    :param seed_for_column_types: a seed used to generate random column types when ``randomize`` is True.

    :returns: an :class:`H2OFrame` object
    """
    t_fraction = U(None, BoundNumeric(0, 1))
    assert_is_type(frame_id, str, None)
    assert_is_type(rows, BoundInt(1))
    assert_is_type(cols, BoundInt(1))
    assert_is_type(randomize, bool)
    assert_is_type(value, numeric)
    assert_is_type(real_range, BoundNumeric(0))
    assert_is_type(real_fraction, t_fraction)
    assert_is_type(categorical_fraction, t_fraction)
    assert_is_type(integer_fraction, t_fraction)
    assert_is_type(binary_fraction, t_fraction)
    assert_is_type(time_fraction, t_fraction)
    assert_is_type(string_fraction, t_fraction)
    assert_is_type(missing_fraction, t_fraction)
    assert_is_type(binary_ones_fraction, t_fraction)
    assert_is_type(factors, BoundInt(1))
    assert_is_type(integer_range, BoundInt(1))
    assert_is_type(has_response, bool)
    assert_is_type(response_factors, None, BoundInt(1))
    assert_is_type(positive_response, bool)
    assert_is_type(seed, int, None)
    assert_is_type(seed_for_column_types, int, None)
    check_frame_id(frame_id)

    if randomize and value:
        raise H2OValueError("Cannot set data to a `value` if `randomize` is true")

    if (categorical_fraction or integer_fraction) and not randomize:
        raise H2OValueError("`randomize` should be True when either categorical or integer columns are used.")

    # The total column fraction that the user has specified explicitly. This sum should not exceed 1. We will respect
    # all explicitly set fractions, and will auto-select the remaining fractions.
    frcs = [real_fraction, categorical_fraction, integer_fraction, binary_fraction, time_fraction, string_fraction]
    wgts = [0.5, 0.2, 0.2, 0.1, 0.0, 0.0]
    sum_explicit_fractions = sum(0 if f is None else f for f in frcs)
    count_explicit_fractions = sum(0 if f is None else 1 for f in frcs)
    remainder = 1 - sum_explicit_fractions
    if sum_explicit_fractions >= 1 + 1e-10:
        raise H2OValueError("Fractions of binary, integer, categorical, time and string columns should add up "
                            "to a number less than 1.")
    elif sum_explicit_fractions >= 1 - 1e-10:
        # The fractions already add up to almost 1. No need to do anything (the server will absorb the tiny
        # remainder into the real_fraction column).
        pass
    else:
        # sum_explicit_fractions < 1  =>  distribute the remainder among the columns that were not set explicitly
        if count_explicit_fractions == 6:
            raise H2OValueError("Fraction of binary, integer, categorical, time and string columns add up to a "
                                "number less than 1.")
        # Each column type receives a certain part (proportional to column's "weight") of the remaining fraction.
        sum_implicit_weights = sum(wgts[i] if frcs[i] is None else 0 for i in range(6))
        for i, f in enumerate(frcs):
            if frcs[i] is not None: continue
            if sum_implicit_weights == 0:
                frcs[i] = remainder
            else:
                frcs[i] = remainder * wgts[i] / sum_implicit_weights
            remainder -= frcs[i]
            sum_implicit_weights -= wgts[i]
    for i, f in enumerate(frcs):
        if f is None:
            frcs[i] = 0
    real_fraction, categorical_fraction, integer_fraction, binary_fraction, time_fraction, string_fraction = frcs

    parms = {"dest": frame_id if frame_id else py_tmp_key(append=h2oconn.session_id),
             "rows": rows,
             "cols": cols,
             "randomize": randomize,
             "categorical_fraction": categorical_fraction,
             "integer_fraction": integer_fraction,
             "binary_fraction": binary_fraction,
             "time_fraction": time_fraction,
             "string_fraction": string_fraction,
             # "real_fraction" is not provided, the backend computes it as 1 - sum(5 other fractions)
             "value": value,
             "real_range": real_range,
             "factors": factors,
             "integer_range": integer_range,
             "binary_ones_fraction": binary_ones_fraction,
             "missing_fraction": missing_fraction,
             "has_response": has_response,
             "response_factors": response_factors,
             "positive_response": positive_response,
             "seed": -1 if seed is None else seed,
             "seed_for_column_types": -1 if seed_for_column_types is None else seed_for_column_types,
             }
    H2OJob(api("POST /3/CreateFrame", data=parms), "Create Frame").poll()
    return get_frame(parms["dest"])