Pandas遍历DataFrame行对

7

如何在Pandas DataFrame中迭代行对?

例如:

content = [(1,2,[1,3]),(3,4,[2,4]),(5,6,[6,9]),(7,8,[9,10])]
df = pd.DataFrame( content, columns=["a","b","interval"])
print df

输出:

   a  b interval
0  1  2   [1, 3]
1  3  4   [2, 4]
2  5  6   [6, 9]
3  7  8  [9, 10]

现在我想做的事情类似于:
for (indx1,row1), (indx2,row2) in df.?
    print "row1:\n", row1
    print "row2:\n", row2
    print "\n"

这应该输出

row1:
a    1
b    2
interval    [1,3]
Name: 0, dtype: int64
row2:
a    3
b    4
interval    [2,4]
Name: 1, dtype: int64

row1:
a    3
b    4
interval    [2,4]
Name: 1, dtype: int64
row2:
a    5
b    6
interval    [6,9]
Name: 2, dtype: int64

row1:
a    5
b    6
interval    [6,9]
Name: 2, dtype: int64
row2:
a    7
b    8
interval    [9,10]
Name: 3, dtype: int64

有没有一种内置的方法可以实现这个? 我查看了df.groupby(df.index // 2)和df.itertuples,但是这些方法似乎都不能实现我的目标。

编辑: 总体目标是获取一个布尔列表,指示列“interval”中的区间是否重叠。 在上面的示例中,该列表将是

overlaps = [True, False, False]

所以每对都需要一个布尔值。

1
你可以尝试使用shift函数,它会返回一个数据框,其中包含“下一行”的数据。 - xyzjayne
1
那么,如何将 df 和 df.shift(1) 结合起来呢? - Lxndr
为什么你想要循环?请发表您的更大问题...您可能不需要循环。 - rafaelc
数据框中的一列包含每行一个区间,我想检查这些区间是否两两重叠。 - Lxndr
1
@Lxndr,你的问题实际上已经被问了很多次(间隔问题)。绝对不需要使用循环来解决这个问题。随着数据框大小的增加,速度会变得非常慢。 - rafaelc
显示剩余2条评论
4个回答

15

将数据框进行平移,并使用axis=1将其与原始数据框连接起来,以便每个时间间隔和下一个时间间隔在同一行中。

df_merged = pd.concat([df, df.shift(-1).add_prefix('next_')], axis=1)
df_merged
#Out:
   a  b interval     next_a     next_b    next_interval
0  1  2   [1, 3]        3.0        4.0           [2, 4]
1  3  4   [2, 4]        5.0        6.0           [6, 9]
2  5  6   [6, 9]        7.0        8.0          [9, 10]
3  7  8  [9, 10]        NaN        NaN              NaN

定义一个与你的列表表示方式配合使用的交叉函数,然后将其应用于合并的数据框中,忽略最后一行其中 shifted_interval 为空的情况。

def intersects(left, right):
    return left[1] > right[0]

df_merged[:-1].apply(lambda x: intersects(x.interval, x.next_interval), axis=1)
#Out:
0     True
1    False
2    False
dtype: bool

1
太棒了!尽管这个回答回答了我的问题,但我会将 @Ben.T 的回答留作已接受的。不过我会将这个用于解决我的问题! - Lxndr

2
如果你想保留循环for,可以使用zipiterrows的方法。
for (indx1,row1),(indx2,row2) in zip(df[:-1].iterrows(),df[1:].iterrows()):
    print "row1:\n", row1
    print "row2:\n", row2
    print "\n"

要同时访问下一行,请使用 df[1:].iterrows() 开始第二个 iterrow,并以此类推。您可以按照所需的方式获得输出。
row1:
a    1
b    2
Name: 0, dtype: int64
row2:
a    3
b    4
Name: 1, dtype: int64


row1:
a    3
b    4
Name: 1, dtype: int64
row2:
a    5
b    6
Name: 2, dtype: int64


row1:
a    5
b    6
Name: 2, dtype: int64
row2:
a    7
b    8
Name: 3, dtype: int64

但是像 @RafaelC 所说,使用 for 循环可能不是解决你的问题的最佳方法。


0

要获得您所展示的输出,请使用以下代码:

for row in df.index[:-1]:
    print 'row 1:'
    print df.iloc[row].squeeze()
    print 'row 2:'
    print df.iloc[row+1].squeeze()
    print

我希望有一个更“Pythonic”的解决方案。对我来说,这看起来像 for i in xrange(len(iterable)): print iterable[i] - Lxndr
@Lxndr,您的请求是以特定方式“打印”,而此方法使用了pandas特定的方法来生成所需的输出。 - zipa

0
你可以尝试使用 iloc 索引。
示例:
for i in range(df.shape[0] - 1):                        
    idx1,idx2=i,i+1                         
    row1,row2=df.iloc[idx1],df.iloc[idx2]   
    print(row1)                             
    print(row2)                             
    print()                                                                            

这与@zipa的答案存在相同的问题。 - Lxndr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接