def fuzzy_c_means(data, m=2, types=2, max_iter=1000, epsilon=1e-6):
    """
    generate binary change map based on FCM
    :param m:
    :param types:
    :param data: cluster data, (1, data_item)
    :param max_iter: intensity number
    :param epsilon: bool, get bcm or not
    :return:
        binary change map
    """
    print('start fuzzy c-means!')
    start_time = time.time()
    data_item = data.shape[1]
    np.random.seed()
    U = np.random.rand(types, data_item)
    U = U / np.sum(U, axis=0, keepdims=True)  # normalization

    repeat_data = np.tile(data, (types, 1))
    expo = -2. / (m - 1)
    for _iter in range(max_iter):
        last_U = np.copy(U)
        # calculate the c cluster centers v with U
        sum_d = np.sum(np.power(U, m) * data, axis=1, keepdims=True)  # (c, data_item)
        sum_w = np.sum(np.power(U, m), axis=1, keepdims=True)
        ctrl = sum_d / sum_w  # (c, 1)
        # calculate the membership matrix U

        distance = np.abs(repeat_data - ctrl)  # (c, data_item)
        distance = distance.astype(dtype=np.float64)

        distance /= np.max(distance, axis=0, keepdims=True)
        distance /= np.min(distance, axis=0, keepdims=True)
        distance = np.power(distance, expo)
        U = distance / np.sum(distance, axis=0, keepdims=True)

        if np.max(np.abs(U - last_U)) < epsilon:
            break

    class_type = np.argmax(U, axis=0)

    class_value_mean = np.array([np.mean(data[:, class_type == 0]), np.mean(data[:, class_type == 1]),
                                 np.mean(data[:, class_type == 2]), np.mean(data[:, class_type == 3])])
    sort_idx = class_value_mean.argsort()

    bwp = np.zeros(data.shape)

    bwp[:, class_type == sort_idx[0]] = 0
    bwp[:, class_type == sort_idx[1]] = 85
    bwp[:, class_type == sort_idx[2]] = 170
    bwp[:, class_type == sort_idx[3]] = 255
    cost_time = time.time() - start_time
    print('fuzzy c-means is done, cost time {:.4}s'.format(cost_time))

    return bwp, class_type

    generate binary change map based on FCM
    :param m:
    :param types:
    :param data: cluster data, (1, data_item)
    :param max_iter: intensity number
    :param epsilon: bool, get bcm or not
    :return:
        binary change map
    
Methodology/util/cluster_util.py