大熊猫的串联系列丢弃重叠的索引

时间:2019-04-30 15:12:06

标签: pandas numpy dataframe series

假设我有以下三个索引重叠的系列

s1 = pd.Series(data=np.arange(5))
s2 = pd.Series(data=np.arange(5),index=np.arange(2,7))
s3 = pd.Series(data=np.arange(5),index=np.arange(5,10))

我希望将它们串联在一起;但是,我希望数据索引包含在具有“最新”索引的系列中的重叠索引中。

因此,在玩具盒中,输出为:

0    0
1    1
2    0
3    1
4    2
5    0
6    1
7    2
8    3
9    4
dtype: int32

这也可以看作是在每个序列与下一个序列重叠的地方剪切每个序列,然后进行串联。当可能有许多大长度的序列时,pandas中是否有一种快速有效的方法来完成此操作。

编辑

我正在寻找一种有效的方式来实现此目的,因为实际上Series的长度和数量都很大,分别约为100k和10k。

5 个答案:

答案 0 :(得分:2)

concatenate用于平坦的索引和Series的值,并使用Series.duplicated进行过滤,并使用~进行倒置掩码:

def new1(series):
    b = [x.index for x in series]
    v = np.concatenate(series)
    i = np.concatenate(b)

    mask = ~pd.Series(i).duplicated(keep='last')
    return pd.Series(v[mask], index=i[mask])

答案 1 :(得分:1)

我建议的最快速度如下:

series = [s1, s2, s3]
s = pd.concat(series)
your_series = s[(~s.index[::-1].duplicated())[::-1]]

您可以比较时间:

import functools

def method1(series):
    s = pd.concat(series)
    return s[(~s.index[::-1].duplicated())[::-1]]

def method2(series):
    s1,s2,s3 = series
    return functools.reduce(pd.Series.combine_first, [s3,s2,s1])

def method3(series):
    s1,s2,s3 = series
    listc = s3.append(s2).append(s1).reset_index().drop_duplicates(
        subset='index', keep='first').set_index('index').sort_index()
    return listc

def method4(series):
    return pd.DataFrame(series).ffill().tail(1).T

结果:

>>> %timeit method1(series)
... 643 µs ± 25.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

>>> %timeit method2(series)
... 1.15 ms ± 26.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

>>> %timeit method3(series)
... 3.09 ms ± 262 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

>>> %timeit method4(series)
... 1.07 ms ± 16.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

当然,当将这些方法应用于更大的数据集时,可能需要考虑它们的内存问题。


编辑:

对更大系列的小测试:

series = [pd.Series(data=np.arange(100000), index=np.arange(i*5000,100000+i*5000)) for i in range(100)]

结果:

>>> %timeit method1(series)
... 583 ms ± 18.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

>>> %timeit method2(series)
... 4.5 s ± 25.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

但是,当序列数较少但每个序列的大小较大时,则差值要小得多

series = [pd.Series(data=np.arange(1000000), index=np.arange(i*5000,1000000+i*5000)) for i in range(10)]

结果:

>>> %timeit method1(series)
... 679 ms ± 23.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

>>> %timeit method2(series)
... 1.39 s ± 26.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

对于比这大得多的任何事情,尽管您可能想考虑使用map-reduce之类的其他方法。

答案 2 :(得分:0)

这是我的看法:

# create a dataframe with all series
df = pd.DataFrame({'s1':s1, 's2':s2, 's3': s3})

# ffill for the latest index:
df.ffill(1)

输出(您期望的是最后一列):

      s1    s2    s3
--  ----  ----  ----
 0     0     0     0
 1     1     1     1
 2     2     0     0
 3     3     1     1
 4     4     2     2
 5   nan     3     0
 6   nan     4     1
 7   nan   nan     2
 8   nan   nan     3
 9   nan   nan     4

一个班轮:

 df = pd.DataFrame([s1,s2,s3]).ffill().tail(1).T

输出:

      2
--  ---
 0    0
 1    1
 2    0
 3    1
 4    2
 5    0
 6    1
 7    2
 8    3
 9    4

答案 3 :(得分:0)

这应该可以解决问题。让我知道:

listc = s3.append(s2).append(s1).reset_index().drop_duplicates(subset='index', keep='first').set_index('index').sort_index()

答案 4 :(得分:0)

使用functools.reducepd.Series.combine_first

import functools

functools.reduce(pd.Series.combine_first,[s3,s2,s1])
Out[794]: 
0    0.0
1    1.0
2    0.0
3    1.0
4    2.0
5    0.0
6    1.0
7    2.0
8    3.0
9    4.0
dtype: float64