选择具有多年观察结果的指数

时间:2018-02-16 01:00:10

标签: python pandas indexing

我希望只选择多年来观察过的行。例如,假设

Codable

我想要的输出是

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

4 个答案:

答案 0 :(得分:4)

filter组使用该组 您可以将返回布尔值的函数传递给

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)

答案 1 :(得分:4)

您可以使用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。

答案 2 :(得分:3)

只是一种新方式

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

答案 3 :(得分:1)

我不相信groupby是必要的:

df = df.sort_index()
df.loc[[i for i in df.index.get_level_values(0).unique() if len(df.loc[i]) > 1]]

#       a   b
# x 0  16   3
#   1  97  36
# t 0   9  18
#   1  37  30

一些基准测试:

df = pd.concat([df]*10000).sort_index()

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]]

%timeit cs(df)   # 19.5ms
%timeit pir(df)  # 33.8ms
%timeit wen(df)  # 17.0ms
%timeit jp(df)   # 22.3ms