重复小于等于算法

时间:2017-10-15 05:07:51

标签: python pandas

我知道一种简单的for - 循环方式来解决这个问题,但我正在寻找一种更好的算法(主要是为了学习。需要这项任务的任务不是关键任务)。我有一组pandas.Series,每个都是可变长度的,所以这必须是动态的。目标是从集合中获取Series,并将其应用于DataFrame的列,并进行大量观察。 Series的名称是应该应用的DataFrame列的名称。应用程序操作是连续的小于等于,所以基本上是:

  1. 按降序对系列进行排序
  2. 对于小于或等于DataFrame中第一个值的相应Series列中的所有值,请指定Series
  3. 中第一个值的索引
  4. 重复,直到系列中的所有值都用尽。
  5. 这是一个玩具示例,只适用于一列:

    输入:

    # 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   ...
    

    同样适用于C2C3 ...

    我现在的解决方案包括一个在循环中执行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)
    

    附加说明:

    1. DataFrameSeries都是由概率流程生成的,因此所有值都将始终位于(0, 1)
    2. 区间内
    3. Series(如果您还没有注意到)是一个累积质量函数,由s.cumsum()/s.sum()
    4. 获得
    5. 函数less_thn_eq实际上是一个反质量函数,它将概率观测值转换为实际观察值。

2 个答案:

答案 0 :(得分:2)

您可能需要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)

答案 1 :(得分:1)

设定:

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]},
                  )

您可以将列作为numpy ndarrays

bounds = s.values
test = df[s.name].values

broadcasting进行比较:

mask = test[:, None] <= bounds

Find the indices

new = mask.argmax(axis = 1)

array indexing与系列&#39;一起使用索引和分配

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]

这仅在对Series值进行排序时才有效。