迭代时使用来自不同行的值的数据框
Data-frame using values from different rows while iterating
底部更新信息
我有一个来自 df.groupby 的小组,看起来像这样:
stop_id stop_name arrival_time departure_time stop_sequence
0 87413013 Gare de Le Havre 05:20:00 05:20:00 0.0
1 87413344 Gare de Bréauté-Beuzeville 05:35:00 05:36:00 1.0
2 87413385 Gare de Yvetot 05:49:00 05:50:00 2.0
3 87411017 Gare de Rouen-Rive-Droite 06:12:00 06:15:00 3.0
4 87384008 Gare de Paris-St-Lazare 07:38:00 07:38:00 4.0
我想循环每一行并使用“stop_name”作为出发地点
然后获取下一行的以下“stop_name”作为到达位置。
最后,我使用下面的函数来解析时间并以秒为单位计算行程持续时间。
def timestrToSeconds(timestr):
ftr = [3600,60,1]
return sum([a*b for a,b in zip(ftr, map(int,timestr.split(':')))])
输出应该是一个包含所有可能组合的数组,如下所示:
result = [
('Gare de Le Havre', 'Gare de Bréauté-Beuzeville', 900),
('Gare de Le Havre', 'Gare de Yvetot', 1740),
('Gare de Le Havre', 'Gare de Rouen-Rive-Droite', 3120),
('Gare de Le Havre', 'Gare de Paris-St-Lazare', 8280),
('Gare de Bréauté-Beuzeville', 'Gare de Yvetot', 780),
('Gare de Bréauté-Beuzeville', 'Gare de Rouen-Rive-Droite', 2160),
('Gare de Bréauté-Beuzeville', 'Gare de Paris-St-Lazare', 7320),
('Gare de Yvetot', 'Gare de Rouen-Rive-Droite', 3120),
('Gare de Yvetot', 'Gare de Paris-St-Lazare', 6480),
('Gare de Rouen-Rive-Droite', 'Gare de Paris-St-Lazare', 4980),
]
我尝试过嵌套循环,但最终对我来说太抽象了。
欢迎任何建议
更新
Mazhar 的解决方案似乎适用于单个组,但是当我像这样遍历我的组时:
timeBetweenStops = []
for group_name, group in xgrouped:
group.arrival_time = pd.to_timedelta(group.arrival_time)
group.departure_time = pd.to_timedelta(group.departure_time)
new_df = group['departure_time'].apply(lambda x: (
group['arrival_time']-x).apply(lambda y: y.total_seconds()))
new_df.index = group.stop_name
new_df.columns = group.stop_name
for i in new_df.index:
for j in new_df.columns:
if new_df.loc[i, j] > 0:
r = (i, j, new_df.loc[i, j])
timeBetweenStops.append(r)
我收到以下错误:
ValueError Traceback (most recent call last)
<ipython-input-196-ec050382d2b5> in <module>
14 for i in new_df.index:
15 for j in new_df.columns:
---> 16 if new_df.loc[i, j] > 0:
17 r = (i, j, new_df.loc[i, j])
18 timeBetweenStopsA.append(r)
~/opt/anaconda3/lib/python3.8/site-packages/pandas/core/generic.py in __nonzero__(self)
1476
1477 def __nonzero__(self):
-> 1478 raise ValueError(
1479 f"The truth value of a {type(self).__name__} is ambiguous. "
1480 "Use a.empty, a.bool(), a.item(), a.any() or a.all()."
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
我曾尝试使用 if np.where(new_df.loc[i, j] > 0): ,但我的结果中有很多不连贯的地方。
我认为您无法在此处避开嵌套循环。可以使用列表理解来做到这一点,但它会更加抽象......
您可以通过以下代码获取结果:
resultat = []
for i, ligne1 in df.iterrows():
depart = ligne1.stop_name
departure_time = ligne1.departure_time
for _, ligne2 in df.iloc[(i + 1):].iterrows():
arrivee = ligne2.stop_name
arrival_time = ligne2.arrival_time
duree = timestrToSeconds(arrival_time) - timestrToSeconds(departure_time)
resultat = resultat + [(depart, arrivee, duree)]
(编辑)此代码在假定车站从出发到到达的顺序的情况下有效。如果不是这种情况,您可以使用以下命令订购数据框:
df = df.sort_values(by = 'departure_time')
在您更新您的问题以便可以使用真实数据检查此代码之前,这是一个解决方案:
all_combs=combinations(df['stop_name'].to_list())
results=[]
for c in all_combs:
results.append((*c,abs(df.loc[df['stop_name']==c[0],'arrival_time']-df.loc[df['stop_name']==c[1],'arrival_time'])))
假设 arrival_time
(或您尝试查看的任何所需列)已经采用 pandas.timedate 格式。如果不是,请看这里并转换为时间日期:
注意:假设您对列中的每个位置都有一个值,此代码有效。
使用 to_timedelta
将您的时间列转换为 Timedelta
df['arrival_time'] = pd.to_timedelta(df['arrival_time'])
df['departure_time'] = pd.to_timedelta(df['departure_time'])
现在使用itertools.combinations
生成所有组合:
from itertools import combinations
comb = lambda x: [
(x.loc[i1, 'stop_name'], x.loc[i2, 'stop_name'],
int((x.loc[i2, 'departure_time'] - x.loc[i1, 'arrival_time']).total_seconds()))
for i1, i2 in combinations(x.index, 2)
]
对于您当前的群组:
>>> comb(df)
[('Gare de Le Havre', 'Gare de Bréauté-Beuzeville', 960),
('Gare de Le Havre', 'Gare de Yvetot', 1800),
('Gare de Le Havre', 'Gare de Rouen-Rive-Droite', 3300),
('Gare de Le Havre', 'Gare de Paris-St-Lazare', 8280),
('Gare de Bréauté-Beuzeville', 'Gare de Yvetot', 900),
('Gare de Bréauté-Beuzeville', 'Gare de Rouen-Rive-Droite', 2400),
('Gare de Bréauté-Beuzeville', 'Gare de Paris-St-Lazare', 7380),
('Gare de Yvetot', 'Gare de Rouen-Rive-Droite', 1560),
('Gare de Yvetot', 'Gare de Paris-St-Lazare', 6540),
('Gare de Rouen-Rive-Droite', 'Gare de Paris-St-Lazare', 5160)]
在许多组中:
>>> df.groupby(...).apply(comb)
1 [(Gare de Le Havre, Gare de Bréauté-Beuzeville...
dtype: object
df.arrival_time = pd.to_timedelta(df.arrival_time)
df.departure_time = pd.to_timedelta(df.departure_time)
new_df = df['departure_time'].apply(lambda x: (
df['arrival_time']-x).apply(lambda y: y.total_seconds()))
new_df.index = df.stop_name
new_df.columns = df.stop_name
for i in new_df.index:
for j in new_df.columns:
if new_df.loc[i, j] > 0:
print(i, j, new_df.loc[i, j])
我认为你可以在没有循环的情况下做到这一点,用一个笨拙的交叉连接代替:
from io import StringIO
import pandas
import numpy
filedata = StringIO("""\
stop_id stop_name arrival_time departure_time stop_sequence
87413013 Gare de Le Havre 05:20:00 05:20:00 0.0
87413344 Gare de Bréauté-Beuzeville 05:35:00 05:36:00 1.0
87413385 Gare de Yvetot 05:49:00 05:50:00 2.0
87411017 Gare de Rouen-Rive-Droite 06:12:00 06:15:00 3.0
87384008 Gare de Paris-St-Lazare 07:38:00 07:38:00 4.0
""")
df = (
pandas.read_csv(filedata, sep="\s\s+", parse_dates=["arrival_time", "departure_time"])
)
results = (
df.merge(df, how="cross")
.loc[lambda df: df["stop_sequence_x"] < df["stop_sequence_y"]]
.assign(travel_time_seconds=lambda df:
df["arrival_time_y"]
.sub(df["departure_time_x"])
.dt.total_seconds()
)
.loc[:, ["stop_name_x", "stop_name_y", "travel_time_seconds"]]
.reset_index(drop=True)
)
这给了我:
stop_name_x stop_name_y travel_time_seconds
0 Gare de Le Havre Gare de Bréauté-Beuzeville 900.0
1 Gare de Le Havre Gare de Yvetot 1740.0
2 Gare de Le Havre Gare de Rouen-Rive-Droite 3120.0
3 Gare de Le Havre Gare de Paris-St-Lazare 8280.0
4 Gare de Bréauté-Beuzeville Gare de Yvetot 780.0
5 Gare de Bréauté-Beuzeville Gare de Rouen-Rive-Droite 2160.0
6 Gare de Bréauté-Beuzeville Gare de Paris-St-Lazare 7320.0
7 Gare de Yvetot Gare de Rouen-Rive-Droite 1320.0
8 Gare de Yvetot Gare de Paris-St-Lazare 6480.0
9 Gare de Rouen-Rive-Droite Gare de Paris-St-Lazare 4980.0
底部更新信息 我有一个来自 df.groupby 的小组,看起来像这样:
stop_id stop_name arrival_time departure_time stop_sequence
0 87413013 Gare de Le Havre 05:20:00 05:20:00 0.0
1 87413344 Gare de Bréauté-Beuzeville 05:35:00 05:36:00 1.0
2 87413385 Gare de Yvetot 05:49:00 05:50:00 2.0
3 87411017 Gare de Rouen-Rive-Droite 06:12:00 06:15:00 3.0
4 87384008 Gare de Paris-St-Lazare 07:38:00 07:38:00 4.0
我想循环每一行并使用“stop_name”作为出发地点 然后获取下一行的以下“stop_name”作为到达位置。 最后,我使用下面的函数来解析时间并以秒为单位计算行程持续时间。
def timestrToSeconds(timestr):
ftr = [3600,60,1]
return sum([a*b for a,b in zip(ftr, map(int,timestr.split(':')))])
输出应该是一个包含所有可能组合的数组,如下所示:
result = [
('Gare de Le Havre', 'Gare de Bréauté-Beuzeville', 900),
('Gare de Le Havre', 'Gare de Yvetot', 1740),
('Gare de Le Havre', 'Gare de Rouen-Rive-Droite', 3120),
('Gare de Le Havre', 'Gare de Paris-St-Lazare', 8280),
('Gare de Bréauté-Beuzeville', 'Gare de Yvetot', 780),
('Gare de Bréauté-Beuzeville', 'Gare de Rouen-Rive-Droite', 2160),
('Gare de Bréauté-Beuzeville', 'Gare de Paris-St-Lazare', 7320),
('Gare de Yvetot', 'Gare de Rouen-Rive-Droite', 3120),
('Gare de Yvetot', 'Gare de Paris-St-Lazare', 6480),
('Gare de Rouen-Rive-Droite', 'Gare de Paris-St-Lazare', 4980),
]
我尝试过嵌套循环,但最终对我来说太抽象了。 欢迎任何建议
更新
Mazhar 的解决方案似乎适用于单个组,但是当我像这样遍历我的组时:
timeBetweenStops = []
for group_name, group in xgrouped:
group.arrival_time = pd.to_timedelta(group.arrival_time)
group.departure_time = pd.to_timedelta(group.departure_time)
new_df = group['departure_time'].apply(lambda x: (
group['arrival_time']-x).apply(lambda y: y.total_seconds()))
new_df.index = group.stop_name
new_df.columns = group.stop_name
for i in new_df.index:
for j in new_df.columns:
if new_df.loc[i, j] > 0:
r = (i, j, new_df.loc[i, j])
timeBetweenStops.append(r)
我收到以下错误:
ValueError Traceback (most recent call last)
<ipython-input-196-ec050382d2b5> in <module>
14 for i in new_df.index:
15 for j in new_df.columns:
---> 16 if new_df.loc[i, j] > 0:
17 r = (i, j, new_df.loc[i, j])
18 timeBetweenStopsA.append(r)
~/opt/anaconda3/lib/python3.8/site-packages/pandas/core/generic.py in __nonzero__(self)
1476
1477 def __nonzero__(self):
-> 1478 raise ValueError(
1479 f"The truth value of a {type(self).__name__} is ambiguous. "
1480 "Use a.empty, a.bool(), a.item(), a.any() or a.all()."
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
我曾尝试使用 if np.where(new_df.loc[i, j] > 0): ,但我的结果中有很多不连贯的地方。
我认为您无法在此处避开嵌套循环。可以使用列表理解来做到这一点,但它会更加抽象......
您可以通过以下代码获取结果:
resultat = []
for i, ligne1 in df.iterrows():
depart = ligne1.stop_name
departure_time = ligne1.departure_time
for _, ligne2 in df.iloc[(i + 1):].iterrows():
arrivee = ligne2.stop_name
arrival_time = ligne2.arrival_time
duree = timestrToSeconds(arrival_time) - timestrToSeconds(departure_time)
resultat = resultat + [(depart, arrivee, duree)]
(编辑)此代码在假定车站从出发到到达的顺序的情况下有效。如果不是这种情况,您可以使用以下命令订购数据框:
df = df.sort_values(by = 'departure_time')
在您更新您的问题以便可以使用真实数据检查此代码之前,这是一个解决方案:
all_combs=combinations(df['stop_name'].to_list())
results=[]
for c in all_combs:
results.append((*c,abs(df.loc[df['stop_name']==c[0],'arrival_time']-df.loc[df['stop_name']==c[1],'arrival_time'])))
假设 arrival_time
(或您尝试查看的任何所需列)已经采用 pandas.timedate 格式。如果不是,请看这里并转换为时间日期:
注意:假设您对列中的每个位置都有一个值,此代码有效。
使用 to_timedelta
Timedelta
df['arrival_time'] = pd.to_timedelta(df['arrival_time'])
df['departure_time'] = pd.to_timedelta(df['departure_time'])
现在使用itertools.combinations
生成所有组合:
from itertools import combinations
comb = lambda x: [
(x.loc[i1, 'stop_name'], x.loc[i2, 'stop_name'],
int((x.loc[i2, 'departure_time'] - x.loc[i1, 'arrival_time']).total_seconds()))
for i1, i2 in combinations(x.index, 2)
]
对于您当前的群组:
>>> comb(df)
[('Gare de Le Havre', 'Gare de Bréauté-Beuzeville', 960),
('Gare de Le Havre', 'Gare de Yvetot', 1800),
('Gare de Le Havre', 'Gare de Rouen-Rive-Droite', 3300),
('Gare de Le Havre', 'Gare de Paris-St-Lazare', 8280),
('Gare de Bréauté-Beuzeville', 'Gare de Yvetot', 900),
('Gare de Bréauté-Beuzeville', 'Gare de Rouen-Rive-Droite', 2400),
('Gare de Bréauté-Beuzeville', 'Gare de Paris-St-Lazare', 7380),
('Gare de Yvetot', 'Gare de Rouen-Rive-Droite', 1560),
('Gare de Yvetot', 'Gare de Paris-St-Lazare', 6540),
('Gare de Rouen-Rive-Droite', 'Gare de Paris-St-Lazare', 5160)]
在许多组中:
>>> df.groupby(...).apply(comb)
1 [(Gare de Le Havre, Gare de Bréauté-Beuzeville...
dtype: object
df.arrival_time = pd.to_timedelta(df.arrival_time)
df.departure_time = pd.to_timedelta(df.departure_time)
new_df = df['departure_time'].apply(lambda x: (
df['arrival_time']-x).apply(lambda y: y.total_seconds()))
new_df.index = df.stop_name
new_df.columns = df.stop_name
for i in new_df.index:
for j in new_df.columns:
if new_df.loc[i, j] > 0:
print(i, j, new_df.loc[i, j])
我认为你可以在没有循环的情况下做到这一点,用一个笨拙的交叉连接代替:
from io import StringIO
import pandas
import numpy
filedata = StringIO("""\
stop_id stop_name arrival_time departure_time stop_sequence
87413013 Gare de Le Havre 05:20:00 05:20:00 0.0
87413344 Gare de Bréauté-Beuzeville 05:35:00 05:36:00 1.0
87413385 Gare de Yvetot 05:49:00 05:50:00 2.0
87411017 Gare de Rouen-Rive-Droite 06:12:00 06:15:00 3.0
87384008 Gare de Paris-St-Lazare 07:38:00 07:38:00 4.0
""")
df = (
pandas.read_csv(filedata, sep="\s\s+", parse_dates=["arrival_time", "departure_time"])
)
results = (
df.merge(df, how="cross")
.loc[lambda df: df["stop_sequence_x"] < df["stop_sequence_y"]]
.assign(travel_time_seconds=lambda df:
df["arrival_time_y"]
.sub(df["departure_time_x"])
.dt.total_seconds()
)
.loc[:, ["stop_name_x", "stop_name_y", "travel_time_seconds"]]
.reset_index(drop=True)
)
这给了我:
stop_name_x stop_name_y travel_time_seconds
0 Gare de Le Havre Gare de Bréauté-Beuzeville 900.0
1 Gare de Le Havre Gare de Yvetot 1740.0
2 Gare de Le Havre Gare de Rouen-Rive-Droite 3120.0
3 Gare de Le Havre Gare de Paris-St-Lazare 8280.0
4 Gare de Bréauté-Beuzeville Gare de Yvetot 780.0
5 Gare de Bréauté-Beuzeville Gare de Rouen-Rive-Droite 2160.0
6 Gare de Bréauté-Beuzeville Gare de Paris-St-Lazare 7320.0
7 Gare de Yvetot Gare de Rouen-Rive-Droite 1320.0
8 Gare de Yvetot Gare de Paris-St-Lazare 6480.0
9 Gare de Rouen-Rive-Droite Gare de Paris-St-Lazare 4980.0