Поведение группы crossfilter.js () в пандах - PullRequest
0 голосов
/ 09 октября 2018

У меня есть демонстрационное приложение, которое использует размеры и группы crossfilter.js для создания графиков с интерактивными фильтрами (очень похоже на демонстрацию времени авиакомпании) http://square.github.io/crossfilter/). Мой реальный набор данных слишком велик, чтобы использовать crossfilter.jsОднако я успешно использовал панд для применения подобной фильтрации к данным.

Однако у меня возникли проблемы с переходом к пониманию того, как моделировать / представлять поведение группы crossfilter в пандах, а именно

группа пересекает текущие фильтры кросс-фильтра, за исключением фильтра соответствующего измерения. https://github.com/square/crossfilter/wiki/API-Reference#group-map-reduce

Например, используя данные транспортного средства:

Make   Year   Color
-------------------
Ford   2000   Red
Honda  2001   Blue
Ford   2001   Green

Если бы я применил фильтр Make: Ford и получил значения для каждого измерения / группы, я бы ожидал:

Make:
  Ford: 2
  Honda: 1
Year:
  2000: 1
  2001: 1
Color:
  Red: 1
  Blue: 0
  Green: 1

Итак, для измерения Make фильтр Make: Ford отбрасывается, чтобы получитьОн применяется для измерений Year и Color, поэтому Blue Honda 2001 года не влияет на счет.

1 Ответ

0 голосов
/ 10 октября 2018

В отсутствие хорошего ответа, это то, что я собрал вместе.Это требует кодирования фильтров в дерево, чтобы его можно было обойти, и соответствующие последовательные фильтры обнуляются при каждом проходе.Я все еще заинтересован в лучших решениях.

Пример вызова, основанный на приведенном выше вопросе, где df - кадр данных панд:

crossfilter(df, ('eq', 'Make', 'Ford'), ['Make', 'Year', 'Color'])

Код:

# filter operators of the form (operator, filter1, filter2)
group_ops = {
    'and': operator.and_,
    'or': operator.or_,
}

# hokie way of forcing all-pass or all-fail filters
nan = float('nan')


# recursive function that turns a tree of python-dict encoded filters into
# bitwise operators for pandas
def build_filter(df, payload, nullify_series=None, nullify_value=True):
    if not payload:
        # no filters, but we have to return something
        # so grab the first series and filter out all NaN values
        return operator.ne(df.ix[:,0], nan)
    op = payload[0]
    if op in value_ops:
        # format: (operator, series, val)
        series = payload[1]
        value = payload[2]
        if series == nullify_series:
            # nullify filter
            if nullify_value:
                # push toward True (e.g. nested in an 'and' operator)
                return operator.ne(df[series], nan)
            else:
                # push toward False (e.g. nested in an 'or' operator)
                return operator.eq(df[series], nan)
        return value_ops[op](df[series], value)
    elif op == 'not':
        # format: ('not', nested_filter)
        value = payload[1]
        return operator.inv(build_filter(df, value, nullify_series, False))
    else:
        # format: (operator, nested_filter_1, nested_filter_2)
        group1 = payload[1]
        group2 = payload[2]
        return group_ops[op](build_filter(df, group1, nullify_series, True),
                             build_filter(df, group2, nullify_series, True))

# returns value counts for all series in `gather`, applying filters in `filters` in all other series
def crossfilter(df, filters, gather):
    df_scoped = df[gather]
    results = { series: df_filtered[series].value_counts().to_dict()
                for series in gather
                for df_filtered in [ df_scoped[build_filter(df_scoped, filters, series)]
                                     if filters else df_scoped ]}
    return results
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...