多年观测指标的选择

2024-10-04 03:21:01 发布

您现在位置:Python中文网/ 问答频道 /正文

我只想选择有跨多年观察结果的行。例如,假设

mlIndx = pd.MultiIndex.from_tuples([('x', 0,),('x',1),('z', 0), ('y', 1),('t', 0),('t', 1)])
df = pd.DataFrame(np.random.randint(0,100,(6,2)), columns = ['a','b'], index=mlIndx)


In [18]: df
Out[18]:
      a   b
x 0   6   1
  1  63  88
z 0  69  54
y 1  27  27
t 0  98  12
  1  69  31

我想要的输出是

Out[19]:
      a   b
x 0   6   1
  1  63  88
t 0  98  12
  1  69  31

我目前的解决方案是直截了当的,所以可以更容易地扩大规模的东西将是伟大的。您可以假设一个排序索引。你知道吗

df.reset_index(level=0, inplace=True)
df[df.level_0.duplicated() | df.level_0.duplicated(keep='last')]

Out[30]:
  level_0   a   b
0       x   6   1
1       x  63  88
0       t  98  12
1       t  69  31

Tags: columnsfromdataframedfindexnprandomout
3条回答

使用分组依据^{}
可以将返回布尔值的函数传递给

df.groupby(level=0).filter(lambda x: len(x) > 1)

      a   b
x 0   7  33
  1  31  43
t 0  71  18
  1  68  72

我把大部分时间都花在速度上了。并非所有的解决方案都需要最快的解决方案。然而,既然这个问题已经提出来了。我会提供我认为应该是一个快速解决方案。我的意图是让未来的读者了解情况。你知道吗

时间测试结果

res.plot(loglog=True)

enter image description here

res.div(res.min(1), 0).T

                      10         30         100         300         1000         3000
cs                4.425970   4.643234   5.422120    3.768960    3.912819     3.937120
wen               2.617455   4.288538   6.694974   18.489803   57.416648   148.860403
jp                6.644870  21.444406  67.315362  208.024627  569.421257  1525.943062
pir               6.043569  10.358355  26.099766   63.531397  165.032540   404.254033
pir_pd_factorize  1.153351   1.132094   1.141539    1.191434    1.000000     1.000000
pir_np_unique     1.058743   1.000000   1.000000    1.000000    1.021489     1.188738
pir_best_of       1.000000   1.006871   1.030610    1.086425    1.068483     1.025837

模拟详细信息

def pir_pd_factorize(df):
    f, u = pd.factorize(df.index.get_level_values(0))
    m = np.bincount(f)[f] > 1
    return df[m]

def pir_np_unique(df):
    u, f = np.unique(df.index.get_level_values(0), return_inverse=True)
    m = np.bincount(f)[f] > 1
    return df[m]

def pir_best_of(df):
    if len(df) > 1000:
        return pir_pd_factorize(df)
    else:
        return pir_np_unique(df)

def cs(df):
    return df[df.groupby(level=0).a.transform('size').gt(1)]

def pir(df):
    return df.groupby(level=0).filter(lambda x: len(x) > 1)

def wen(df):
    s=df.a.count(level=0)
    return df.loc[s[s>1].index.tolist()]

def jp(df):
    return df.loc[[i for i in df.index.get_level_values(0).unique() if len(df.loc[i]) > 1]]


res = pd.DataFrame(
    index=[10, 30, 100, 300, 1000, 3000],
    columns='cs wen jp pir pir_pd_factorize pir_np_unique pir_best_of'.split(),
    dtype=float
)

np.random.seed([3, 1415])
for i in res.index:
    d = pd.DataFrame(
        dict(a=range(i)),
        pd.MultiIndex.from_arrays([
            np.random.randint(i // 4 * 3, size=i),
            range(i)
        ])
    )
    for j in res.columns:
        stmt = f'{j}(d)'
        setp = f'from __main__ import d, {j}'
        res.at[i, j] = timeit(stmt, setp, number=100)

您可以使用groupby(在索引的第一级)+transform来解决这个问题,然后使用布尔索引来过滤这些行:

df[df.groupby(level=0).a.transform('size').gt(1)]

      a   b
x 0  67  83
  1   2  34
t 0  18  87
  1  63  20

细节 输出groupby-

df.groupby(level=0).a.transform('size')

x  0    2
   1    2
z  0    1
y  1    1
t  0    2
   1    2
Name: a, dtype: int64

从这里进行筛选很简单,只需找到大小大于1的行即可。你知道吗

只是一种新的方式

s=df.a.count(level=0)

df.loc[s[s>1].index.tolist()]
Out[12]: 
      a   b
x 0   1  31
  1  70  29
t 0  42  26
  1  96  29

如果你想继续使用复制品

s=df.index.get_level_values(level=0)

df.loc[s[s.duplicated()].tolist()]
Out[18]: 
      a   b
x 0   1  31
  1  70  29
t 0  42  26
  1  96  29

相关问题 更多 >