Использование панд для суммирования численных различий в одном столбце - PullRequest
0 голосов
/ 09 января 2019

Я просматриваю данные турникета MTA для метро Нью-Йорка и пытаюсь выяснить, каков общий трафик для каждой станции. Каждая станция имеет несколько уникальных турникетов, и учитываются как входы, так и выходы. Я хочу суммировать входы и выходы для каждой станции, чтобы определить трафик за данный период времени.

Уникальный турникет определяется комбинацией идентификатора в столбце SCP и имени в столбце STATION. Номера трафика турникета являются кумулятивными, поэтому для заданного периода времени (скажем, дня) вам нужно найти начальное значение, вычесть его из конечного значения и суммировать все эти различия для каждого турникета на станции, чтобы получить трафик для станция.

DataFrame выглядит следующим образом:

    C/A    UNIT        SCP   STATION    LINENAME    DIVISION    DATE TIME   DESC    ENTRIES EXITS   NEW_DATE
0   A002    R051    02-00-00    59 ST   NQR456W BMT 04/28/2018  00:00:00    REGULAR 6598847 2235829 2018-04-28
1   A002    R051    02-00-00    59 ST   NQR456W BMT 04/28/2018  04:00:00    REGULAR 6598864 2235830 2018-04-28
2   A002    R051    02-00-00    59 ST   NQR456W BMT 04/28/2018  08:00:00    REGULAR 6598880 2235863 2018-04-28
3   A002    R051    02-00-00    59 ST   NQR456W BMT 04/28/2018  12:00:00    REGULAR 6598961 2235955 2018-04-28
4   A002    R051    02-00-00    59 ST   NQR456W BMT 04/28/2018  16:00:00    REGULAR 6599175 2236015 2018-04-28

До сих пор я пробовал различные комбинации df.groupby(['SCP', 'STATION']), но я не могу понять, как правильно группировать или применять другие методы для получения результата суммированных разностей на станцию.

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

STATION   | DATE                | ENTRIES | EXITS | TOTALS |     
CHURCH AV | 2018-04-28 00:00:00 | 12948   | 9076  | 22024  |
59 ST     | 2018-04-28 00:00:00 | 20401   | 17907 | 38308  |

Обратите внимание, что ВХОДЫ и ВЫХОДЫ не начинаются с 0, но были накоплены с течением времени, поэтому первые две записи в наборе данных выглядят так, как показано ниже. Обратите внимание, что я маскирую (...) не важные столбцы здесь для удобства чтения:

...  |   SCP   | STATION | ... |    DATE     |   TIME   | ...   | ENTRIES | EXITS  |
...  |02-00-00 | 59 ST   | ... |  2018-04-28 | 00:00:00 | ...   | 6598847 | 2235829|
...  |02-00-00 | 59 ST   | ... |  2018-04-28 | 04:00:00 | ...   | 6598864 | 2235830|

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

    # Importing and cleaning data
    may05_2018 = pd.read_csv('http://web.mta.info/developers/data/nyct/turnstile/turnstile_180505.txt')

    # Only including one of the several files for this example
    source_data = [may05_2018] 

    # Clean data
    all_converted_data = []
    for i in source_data:
        converted = i 
        converted['DATE'] = pd.to_datetime(i['DATE'] + ' ' + i['TIME'])
        converted.drop('TIME', axis=1, inplace=True)
        converted.rename(columns = lambda x: x.strip(), inplace=True)   
        all_converted_data.append(converted)

    # Create copy of data frame to maintain the original
    test_df = df.copy()

    # Function for calculating differences
    def mta_traffic(data, freq='D'):
        data.ENTRIES = data.ENTRIES - data.shift(1).ENTRIES
        data.EXITS = data.EXITS - data.shift(1).EXITS
        data = data.set_index(['STATION', 'SCP'])[['ENTRIES', 'EXITS', 'DATE']]
        data = data.resample(freq, on='DATE').sum()
        return data

    # Create df of data sums. These seem to generate legit values.
    test_df = test_df.groupby(['STATION', 'SCP']).apply(mta_traffic)

    # Add TOTALS column, the sum of ENTRIES and EXITS
    test_df['TOTALS'] = test_df['ENTRIES'] + test_df['EXITS']

    # Attempt to groupby STATION and find the sums per station
    station_traffic = test_df.groupby('STATION')['TOTALS'].sum()

OUT

    STATION
    1 AV               2.135754e+06
    103 ST             4.971873e+08
    103 ST-CORONA      1.528737e+06
    104 ST            -5.682778e+09
    110 ST             9.083200e+05
    111 ST             3.939572e+07
    116 ST            -3.635802e+09

И вот где ценности сходят с ума. Некоторым кажется, что они могут быть законными, но другие, как и отрицательные, определенно ошибаются.

Прямо сейчас я пытаюсь выяснить, почему группировка по STATION по результату генерирует неверные значения, тогда как несгруппированные результаты кажутся хорошими. Опять же, в конечном итоге я хочу выводить трафик на СТАНЦИЮ в разные периоды времени и интервалы.

1 Ответ

0 голосов
/ 09 января 2019

Пример данных:

        SCP STATION        DATE      TIME  ENTRIES   EXISTS    NEW_DATE
0  02-00-00   59 ST  04/28/2018  00:00:00  6598847  2235829  2018-04-28
1  02-00-00   59 ST  04/28/2018  04:00:00  6598864  2235830  2018-04-28
2  02-00-00   59 ST  04/28/2018  08:00:00  6598880  2235863  2018-04-28
3  02-00-00   59 ST  04/28/2018  12:00:00  6598961  2235955  2018-04-28
4  02-00-00   59 ST  04/28/2018  16:00:00  6599175  2236015  2018-04-28

Я рекомендую сделать это, чтобы даты были в хорошем представлении:

series.DATE = pd.to_datetime(series.DATE) + pd.to_timedelta(series.TIME)

series = series.drop(['TIME', 'NEW_DATE'], 1)

Из:

        SCP STATION                DATE  ENTRIES   EXISTS
0  02-00-00   59 ST 2018-04-28 00:00:00  6598847  2235829
1  02-00-00   59 ST 2018-04-28 04:00:00  6598864  2235830
2  02-00-00   59 ST 2018-04-28 08:00:00  6598880  2235863
3  02-00-00   59 ST 2018-04-28 12:00:00  6598961  2235955
4  02-00-00   59 ST 2018-04-28 16:00:00  6599175  2236015

Чтобы сделать то, что вы хотите с сгруппированными данными, вы можете определить свою функцию, например:

def function(series, freq='D'):
    series.ENTRIES = series.ENTRIES - series.shift(1).ENTRIES
    series.EXISTS = series.EXISTS - series.shift(1).EXISTS
    series = series.set_index(['SCP', 'STATION'])[['ENTRIES', 'EXISTS', 'DATE']]
    series = series.resample(freq, on='DATE').sum()
    return series

А затем используйте его с groupby:

series.groupby(['SCP','STATION']).apply(function)

Из:

                             ENTRIES  EXISTS
SCP      STATION DATE                       
02-00-00 59 ST   2018-04-28    328.0   186.0

(здесь первые 3 столбца - индекс)

Также вы можете передавать аргументы (например, вы хотите иметь частоту 3 часа):

series.groupby(['SCP','STATION']).apply(function, freq='3H')

Из:

                                      ENTRIES  EXISTS
SCP      STATION DATE                                
02-00-00 59 ST   2018-04-28 00:00:00      0.0     0.0
                 2018-04-28 03:00:00     17.0     1.0
                 2018-04-28 06:00:00     16.0    33.0
                 2018-04-28 09:00:00      0.0     0.0
                 2018-04-28 12:00:00     81.0    92.0
                 2018-04-28 15:00:00    214.0    60.0

Но с этим примером будьте осторожны в первом сырье. В функции я использую shift для вычитания с предыдущим необработанным (я не знаю, как ваши данные выглядят при запуске, поэтому у нас есть NaN для первого необработанного, потому что у него нет предыдущего необработанного).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...