使用熊猫求和同一列中的数值差异

时间:2019-01-09 07:25:31

标签: python pandas dataframe

我正在查看纽约市地铁的MTA转闸数据,并试图找出每个站点的总流量。每个站都有许多独特的旋转门,并且入口和出口均被计数。我想对每个站点的入口和出口求和,以确定给定时间段内的交通量。

唯一的旋转门由SCP列中的ID和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  |

请注意,ENTRIES和EXITS并非从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 :(得分:0)

数据示例:

        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个小时的频率):

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用作第一原始数据,因为它没有先前的原始数据。)