我知道一个简单的for-loopy方法来解决这个问题,但是我正在寻找一个更好的算法(主要是为了学习)。这个任务需要的不是关键任务)。我有一组可变长度的pandas.Series,所以这必须是动态的。目标是从集合中获取一个Series,并将其应用到DataFrame的一个列中,其中包含大量的观察结果。Series的名称是它应该应用到的DataFrame列的名称。应用程序操作是逐次小于等于的,因此基本上:
DataFrame列中小于或等于Series中的第一个值的所有值,指定Series中第一个值的索引。下面是一个玩具示例,只适用于一列:
输入:
# DataFrame (length is constant) | Series (length can change)
C1 C2 C3 C4 ... | Val
ID | IDX
0 0.20 0.30 0.10 0.25 ... | A0 0.20
1 0.15 0.04 0.40 0.30 ... | A1 0.55
2 0.65 0.83 0.88 0.61 ... | A2 0.90
3 0.15 0.55 0.45 0.26 ... | A3 1.00
4 0.78 0.83 0.89 0.12 ... | name: C1 # (Note name matches column name)
5 0.84 0.75 0.39 0.80 ... |
6 0.99 0.83 0.45 0.16 ... |
(more than 10^7 observations, and about 15 columns)输出:
# DataFrame
C1 C2 C3 C4 ...
ID
0 A0 0.30 0.10 0.25 ...
1 A0 0.04 0.40 0.30 ...
2 A2 0.83 0.88 0.61 ...
3 A0 0.55 0.45 0.26 ...
4 A2 0.83 0.89 0.12 ...
5 A2 0.75 0.39 0.80 ...
6 A3 0.83 0.45 0.16 ...同样对于C2,C3..。
我目前的解决方案包括一个在循环中执行greater-than函数应用程序的函数,并使用pandas.DataFrame.transform函数进行调用,如下所示:
def less_thn_eq(col, s):
op = s.copy()
for i, v in s.sort_values(ascending=False).iteritems():
op.loc[s <= v] = i
trans_funcs = dict([(s.name, partial(less_thn_eq, s=s)) for s in series_set])
df.transform(trans_funcs)补充说明:
DataFrame和Series都是由概率过程产生的,因此所有的值都在间隔(0, 1)中。Series (如果您还没有注意到)是一个累积质量函数,由s.cumsum()/s.sum()获得less_thn_eq实际上是一个逆质量函数,它将概率观测转化为实际观测。发布于 2017-10-15 06:13:00
您可能需要numpy数字化功能。如果您的玩具示例输出中有错误(“A1”可能应该是“A2”),那么下面的内容将是快速的。
# setup toy example
df = pd.DataFrame( np.array([
0.20, 0.30, 0.10, 0.25,
0.15, 0.04, 0.40, 0.30,
0.65, 0.83, 0.88, 0.61,
0.15, 0.55, 0.45, 0.26,
0.78, 0.83, 0.89, 0.12,
0.84, 0.75, 0.39, 0.80,
0.99, 0.83, 0.45, 0.16]).reshape(7,4), columns=['C1', 'C2', 'C3', 'C4'])
bins = pd.Series ([0.20, 0.55, 0.90, 1.00], index=['A0', 'A1', 'A2', 'A3'])
# perform digitization
eps = 10**-7
bin_indices = pd.Series(bins.index)
indices = np.digitize(df, bins+eps)
(bin_indices[indices.flatten()]).reshape( df.shape )
Out[94]:
array([['A0', 'A1', 'A0', 'A1'],
['A0', 'A0', 'A1', 'A1'],
['A2', 'A2', 'A2', 'A2'],
['A0', 'A1', 'A1', 'A1'],
['A2', 'A2', 'A2', 'A0'],
['A2', 'A2', 'A1', 'A2'],
['A3', 'A2', 'A1', 'A0']], dtype=object)发布于 2017-10-15 05:54:21
设置:
import pandas as pd
import numpy as np
s = pd.Series([0.20,0.55,0.90,1.00], index = ['A0','A1','A2','A3'], name = 'C1')
df = pd.DataFrame({'C1':[0.20,0.15,0.65,0.15,0.78,0.84,0.99],
'C2':[0.30,0.04,0.83,0.55,0.83,0.75,0.83],
'C3':[0.10,0.40,0.88,0.45,0.89,0.39,0.45],
'C4':[0.25,0.30,0.61,0.26,0.12,0.80,0.16]},
)你可以把这些列作为矮胖的长条
bounds = s.values
test = df[s.name].values用广播业进行比较
mask = test[:, None] <= boundsnew = mask.argmax(axis = 1)将数组索引与系列索引一起使用并分配
df[s.name] = s.index[new]
>>> df
C1 C2 C3 C4
0 A0 0.30 0.10 0.25
1 A0 0.04 0.40 0.30
2 A2 0.83 0.88 0.61
3 A0 0.55 0.45 0.26
4 A2 0.83 0.89 0.12
5 A2 0.75 0.39 0.80
6 A3 0.83 0.45 0.16
>>>如果您想在整个DataFrame上使用Series执行该操作
bounds = s.values
mask = df.values[..., None] <= bounds
new = mask.argmax(axis = 2)
df[df.columns] = s.index[new]只有在对系列值进行排序的情况下,这才能工作。
https://stackoverflow.com/questions/46751910
复制相似问题