Return a list of {feat_id: value} dicts with feature weights, 
    following ideas from  http://blog.datadive.net/interpreting-random-forests/

def _get_prediction_feature_weights(lgb, X, n_targets):
    """ 
    Return a list of {feat_id: value} dicts with feature weights, 
    following ideas from  http://blog.datadive.net/interpreting-random-forests/  
    """
    if n_targets == 2:
        n_targets = 1
    dump = lgb.booster_.dump_model()
    tree_info = dump['tree_info']
    _compute_node_values(tree_info)
    pred_leafs = lgb.booster_.predict(X, pred_leaf=True).reshape(-1, n_targets)
    tree_info = np.array(tree_info).reshape(-1, n_targets)
    assert pred_leafs.shape == tree_info.shape

    res = []
    for target in range(n_targets):
        feature_weights = defaultdict(float)  # type: DefaultDict[Optional[str], float]
        for info, leaf_id in zip(tree_info[:, target], pred_leafs[:, target]):
            leaf_index, split_index = _get_leaf_split_indices(
                info['tree_structure']
            )
            bias, path = _get_decision_path(leaf_index, split_index, leaf_id)
            feature_weights[None] += bias
            for feat, value in path:
                feature_weights[feat] += value
        res.append(dict(feature_weights))
    return res