假设我有以下三个索引重叠的系列
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。
答案 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.reduce
和pd.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