迭代时使用来自不同行的值的数据框

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