连接pandas中的连接系列丢掉重叠的索引

问题描述 投票:3回答:5

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

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做到这一点,当可能有很多系列的长度。

编辑

我正在寻找一种有效的方法来实现这一点,因为实际上系列的长度和数量都很大,分别约为100k和10k。

pandas numpy dataframe series
5个回答
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
投票

我建议的最快速度如下:

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作为一种可能性。


0
投票

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

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

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

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
© www.soinside.com 2019 - 2024. All rights reserved.