TL;DR
iloc
+ argsort
我们可以使用以下方法来解决这个问题iloc http://pandas.pydata.org/pandas-docs/version/0.17.0/generated/pandas.DataFrame.iloc.html我们可以在其中获取序数位置数组并返回按这些位置重新排序的数据帧。
凭借的力量iloc http://pandas.pydata.org/pandas-docs/version/0.17.0/generated/pandas.DataFrame.iloc.html, 我们可以sort
与任何指定顺序的数组。
现在,我们需要做的就是确定获取此排序的方法。原来有一个方法叫做argsort http://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.argsort.html这正是这样做的。通过传递结果argsort http://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.argsort.html to iloc http://pandas.pydata.org/pandas-docs/version/0.17.0/generated/pandas.DataFrame.iloc.html,我们可以整理我们的数据框。
实施例1
使用上面指定的问题
df.iloc[df.prod(1).argsort()]
与上面的结果相同
A B
0 0 1
1 1 2
2 2 1
4 4 1
3 3 2
5 5 2
这是为了简单起见。如果性能是一个问题,我们可以进一步采取这一措施,并重点关注numpy
v = df.values
a = v.prod(1).argsort()
pd.DataFrame(v[a], df.index[a], df.columns)
这些解决方案的速度有多快?
我们可以看到pd_ext_sort
是最简洁的,但扩展性不如其他。
np_ext_sort
以牺牲透明度为代价提供最佳性能。不过,我认为发生的事情仍然非常清楚。
回测设置
def add_drop():
return df.assign(P=df.prod(1)).sort_values('P').drop('P', 1)
def pd_ext_sort():
return df.iloc[df.prod(1).argsort()]
def np_ext_sort():
v = df.values
a = v.prod(1).argsort()
return pd.DataFrame(v[a], df.index[a], df.columns)
results = pd.DataFrame(
index=pd.Index([10, 100, 1000, 10000], name='Size'),
columns=pd.Index(['add_drop', 'pd_ext_sort', 'np_ext_sort'], name='method')
)
for i in results.index:
df = pd.DataFrame(np.random.rand(i, 2), columns=['A', 'B'])
for j in results.columns:
stmt = '{}()'.format(j)
setup = 'from __main__ import df, {}'.format(j)
results.set_value(i, j, timeit(stmt, setup, number=100))
results.plot()
实施例2
假设我有一列负值和正值。我想按增加的幅度进行排序......但是,我希望负面因素首先出现。
假设我有数据框df
df = pd.DataFrame(dict(A=range(-2, 3)))
print(df)
A
0 -2
1 -1
2 0
3 1
4 2
我会再次设置3个版本。这次我要用np.lexsort
它返回与以下相同类型的数组argsort
。意思是,我可以用它来重新排序数据框。
Caveat: np.lexsort
首先按列表中的最后一个数组排序。\shurg
def add_drop():
return df.assign(P=df.A >= 0, M=df.A.abs()).sort_values(['P', 'M']).drop(['P', 'M'], 1)
def pd_ext_sort():
v = df.A.values
return df.iloc[np.lexsort([np.abs(v), v >= 0])]
def np_ext_sort():
v = df.A.values
a = np.lexsort([np.abs(v), v >= 0])
return pd.DataFrame(v[a, None], df.index[a], df.columns)
全部返回
A
1 -1
0 -2
2 0
3 1
4 2
这次有多快?
在这个例子中,两者pd_ext_sort
and np_ext_sort
表现优于add_drop
.
回测设置
results = pd.DataFrame(
index=pd.Index([10, 100, 1000, 10000], name='Size'),
columns=pd.Index(['add_drop', 'pd_ext_sort', 'np_ext_sort'], name='method')
)
for i in results.index:
df = pd.DataFrame(np.random.randn(i, 1), columns=['A'])
for j in results.columns:
stmt = '{}()'.format(j)
setup = 'from __main__ import df, {}'.format(j)
results.set_value(i, j, timeit(stmt, setup, number=100))
results.plot(figsize=(15, 6))