我正在查看纽约市地铁的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对结果进行分组会生成错误的值,而对未分组的结果似乎没问题。再一次,最终我想在不同的时间范围和间隔内输出每个站点的流量。
答案 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
用作第一原始数据,因为它没有先前的原始数据。)