<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def estimate_conditional_information(x, y, z):
 """ Estimate the conditional mutual information of three datasets. Conditional mutual information is the mutual information of two datasets, given a third: $ I(x;y|z) = H(x,z) + H(y,z) - H(x,y,z) - H(z) $ Where H(x) is the Shannon entropy of x. For continuous datasets, adapts the Kraskov Estimator [1] for mutual information. Equation 8 still holds because the epsilon terms cancel out: Let d_x, represent the dimensionality of the continuous portion of x. Then, we see that: d_xz + d_yz - d_xyz - d_z = (d_x + d_z) + (d_y + d_z) - (d_x + d_y + d_z) - d_z = 0 Args: x (array-like):
 An array with shape (n_samples, n_features_x) y (array-like):
 An array with shape (n_samples, n_features_y) z (array-like):
 An array with shape (n_samples, n_features_z). This is the dataset being conditioned on. Returns: float: A floating point number representing the conditional mutual information of x and y given z. This calculation is *exact* for entirely discrete datasets and *approximate* if there are continuous columns present. References: .. [1] A. Kraskov, H. Stogbauer and P. Grassberger, "Estimating mutual information". Phys. Rev. E 69, 2004. """

    xz = np.concatenate((x, z), axis=1)
    yz = np.concatenate((y, z), axis=1)
    xyz = np.concatenate((xz, y), axis=1)
    epsilon = _calculate_epsilon(xyz)
    h_xz = estimate_entropy(xz, epsilon)
    h_yz = estimate_entropy(yz, epsilon)
    h_xyz = estimate_entropy(xyz, epsilon)
    h_z = estimate_entropy(z, epsilon)
    return max(0, h_xz + h_yz - h_xyz - h_z)