假设我有pd.Series
import pandas as pd
import numpy as np
s = pd.Series(np.arange(10), list('abcdefghij'))
我希望通过将上半部分与下半部分交织来“洗牌”这个系列,就像一副牌。
我希望这样的结果
a 0
f 5
b 1
g 6
c 2
h 7
d 3
i 8
e 4
j 9
dtype: int32
结论
最终功能
def perfect_shuffle(s):
n = s.values.shape[0] # get length of s
l = (n + 1) // 2 * 2 # get next even number after n
# use even number to reshape and only use n of them after ravel
a = np.arange(l).reshape(2, -1).T.ravel()[:n]
# construct new series slicing both values and index
return pd.Series(s.values[a], s.index.values[a])
演示
s = pd.Series(np.arange(11), list('abcdefghijk'))
print(perfect_shuffle(s))
a 0
g 6
b 1
h 7
c 2
i 8
d 3
j 9
e 4
k 10
f 5
dtype: int64
order='F'
vs T
我建议使用T.ravel()
而不是ravel(order='F')
经过调查,它几乎不重要,但ravel(order='F')
对于更大的阵列更好。
d = pd.DataFrame(dict(T=[], R=[]))
for n in np.power(10, np.arange(1, 8)):
a = np.arange(n).reshape(2, -1)
stamp = pd.datetime.now()
for _ in range(100):
a.ravel(order='F')
d.loc[n, 'R'] = (pd.datetime.now() - stamp).total_seconds()
stamp = pd.datetime.now()
for _ in range(100):
a.T.ravel()
d.loc[n, 'T'] = (pd.datetime.now() - stamp).total_seconds()
d
d.plot()
感谢 unutbu 和 Warren Weckesser
答案 0 :(得分:5)
在系列长度均匀的特殊情况下,您可以通过将其值重新整形为两行,然后使用perfectly shuffle以Fortran顺序读取项目来执行ravel(order='F')
:
In [12]: pd.Series(s.values.reshape(2,-1).ravel(order='F'), s.index)
Out[12]:
a 0
b 5
c 1
d 6
e 2
f 7
g 3
h 8
i 4
j 9
dtype: int64
Fortran命令使最左边的轴增量最快。所以在2D数组中 在进行到之前,通过向下移动一列的行来读取值 下一栏。与此相比,这具有交错值的效果 通常的C阶。
在一般情况下,系列的长度可能是奇数, 也许最快的方法是使用移位切片重新分配值:
import numpy as np
import pandas as pd
def perfect_shuffle(ser):
arr = ser.values
result = np.empty_like(arr)
N = (len(arr)+1)//2
result[::2] = arr[:N]
result[1::2] = arr[N:]
result = pd.Series(result, index=ser.index)
return result
s = pd.Series(np.arange(11), list('abcdefghijk'))
print(perfect_shuffle(s))
产量
a 0
b 6
c 1
d 7
e 2
f 8
g 3
h 9
i 4
j 10
k 5
dtype: int64
答案 1 :(得分:2)
要添加@unutbu的回答,一些基准测试:
>>> import timeit
>>> import numpy as np
>>>
>>> setup = '''
... import pandas as pd
... import numpy as np
... s = pd.Series(list('abcdefghij'), np.arange(10))
... '''
>>>
>>> funcs = ['s[np.random.permutation(s.index)]', "pd.Series(s.values.reshape(2,-1).ravel(order='F'), s.index)",
... 's.iloc[np.random.permutation(s.index)]', "s.values.reshape(-1, 2, order='F').ravel()"]
>>>
>>> for f in funcs:
... print(f)
... print(min(timeit.Timer(f, setup).repeat(3, 50)))
...
s[np.random.permutation(s.index)]
0.029795593000017107
pd.Series(s.values.reshape(2,-1).ravel(order='F'), s.index)
0.0035402200010139495
s.iloc[np.random.permutation(s.index)]
0.010904800990829244
s.values.reshape(-1, 2, order='F').ravel()
0.00019640100072138011
f
中的最终funcs
是>比第一个np.random.permutation
方法快99%,所以这可能是你最好的选择。