问题 如何逐个创建DataFrame切片对象?


我有一个DataFrame,我想从中选择某些行和列。我知道如何使用 loc。但是,我希望能够单独指定每个条件,而不是一次性指定。

import numpy as np
import pandas as pd
idx = pd.IndexSlice

index = [np.array(['foo', 'foo', 'qux', 'qux']),
         np.array(['a', 'b', 'a', 'b'])]
columns = ["A",  "B"]
df = pd.DataFrame(np.random.randn(4, 2), index=index, columns=columns)
print df
print df.loc[idx['foo', :], idx['A':'B']]

              A         B
foo a  0.676649 -1.638399
    b -0.417915  0.587260
qux a  0.294555 -0.573041
    b  1.592056  0.237868


              A         B
foo a -0.470195 -0.455713
    b  1.750171 -0.409216

需求

我希望能够通过以下代码来实现相同的结果,我将逐一指定每个条件。我能够使用一个也很重要 slice_list 允许动态行为[即无论是否有两个,三个或十个不同的标准,语法应该有效 slice_list]。

slice_1 = 'foo'
slice_2 = ':'
slice_list = [slice_1, slice_2]

column_slice = "'A':'B'"
print df.loc[idx[slice_list], idx[column_slice]]

1966
2018-03-23 16:30


起源

slice_2是否意味着在第二个索引(例如,a,b)或第一个索引(foo,qux)上进行切片? - Jammeth_Q
只是第二个。 - bluprince13
您可以从中激发灵感,其中eval用于数据帧中的多个条件: stackoverflow.com/questions/33699886/... - WNG
你是如何生成切片列表的?动态还是手动?我很乐意扩大我的答案,并帮助你更多。 - Jammeth_Q
@Jammeth_Q动态。我要做的是对于任何给定的数据框是检查有多少级别,然后对于每个级别我要求用户定义用户想要的那个级别的片段。如果用户没有指定任何内容,我将默认为该级别的第一个项目。最后,我需要创建一个组合所有单个切片的pd.IndexSlice。这就是为什么它需要是动态的。 - bluprince13


答案:


建立起来 Ted Petrou的答案

slices = [('foo', slice(None)), slice('A', 'B')]
print df.loc[tuple(idx[s] for s in slices)]

              A         B
foo a -0.465421 -0.591763
    b -0.854938  1.221204

slices = [('foo', slice(None)), 'A']
print df.loc[tuple(idx[s] for s in slices)]

foo  a   -0.465421
     b   -0.854938
Name: A, dtype: float64

slices = [('foo', slice(None))]
print df.loc[tuple(idx[s] for s in slices)]

              A         B
foo a -0.465421 -0.591763
    b -0.854938  1.221204

你必须在打电话时使用元组 __getitem__ (loc[...])带有“动态”参数。

你也可以避免建立 slice 手工对象:

def to_selector(s):
    if isinstance(s, tuple) or isinstance(s, list):
        return tuple(map(to_selector, s))
    ps = [None if len(p) == 0 else p for p in s.split(':')]
    assert len(ps) > 0 and len(ps) <= 2
    if len(ps) == 1:
        assert ps[0] is not None
        return ps[0]
    return slice(*ps)

query = [('foo', ':'), 'A:B']
df.loc[tuple(idx[to_selector(s)] for s in query)]

1
2018-04-11 15:18





你可以使用 slice 内置功能。您不能使用字符串构建切片,因为':'是文字字符而不是合成字符。

slice_1 = 'foo'
slice_2 = slice(None)
column_slice = slice('A', 'B')
df.loc[idx[slice_1, slice_2], idx[column_slice]]

9
2018-03-23 16:38



谢谢!但是,我希望能够使用切片列表,而不是指定每个切片。问题已更新! - bluprince13
嗨,您是否有机会知道如何使用切片列表使其更加动态而不是命名单个切片? - bluprince13


你可能不得不建立你的“切片列表”与你想要的有点不同,但这是一个相对紧凑的方法使用 df.merge() 和 df.ix[]

# Build a "query" dataframe
slice_df = pd.DataFrame(index=[['foo','qux','qux'],['a','a','b']])
# Explicitly name columns
column_slice = ['A','B']

slice_df.merge(df, left_index=True, right_index=True, how='inner').ix[:,column_slice]

Out[]: 
              A         B
foo a  0.442302 -0.949298
qux a  0.425645 -0.233174
    b -0.041416  0.229281

不幸的是,此方法还要求您明确第二个索引和列。但是如果你问得好的话,计算机很适合为你制作冗长乏味的列表。

编辑 - 动态构建可以像上面一样使用的切片列表的方法示例。

这是一个函数,它接受一个数据帧并吐出一个列表,然后可以用它来创建一个“查询”数据帧来切割原始数据。它仅适用于具有1或2个索引的数据帧。如果这是一个问题,请告诉我。

def make_df_slice_list(df):
    if df.index.nlevels == 1:
        slice_list = []
        # Only one level of index
        for dex in df.index.unique():
            if input("DF index: " + dex + " - Include? Y/N: ") == "Y":
                # Add to slice list
                slice_list.append(dex)
    if df.index.nlevels > 1:
        slice_list = [[] for _ in xrange(df.index.nlevels)]
        # Multi level
        for i in df.index.levels[0]:
            print "DF index:", i, "has subindexes:", [dex for dex in df.ix[i].index]
            sublist = input("Enter a the indexes you'd like as a list: ")
            # if no response, the first entry
            if len(sublist)==0:
                sublist = [df.ix[i].index[0]]
            # Add an entry to the first index list for each sub item passed
            [slice_list[0].append(i) for item in sublist]
            # Add each of the second index list items
            [slice_list[1].append(item) for item in sublist]
    return slice_list

我并不是说这是一种与用户沟通的方式,只是一个例子。当你使用它时,你必须传递字符串(例如 "Y" 和 "N")和字符串列表(["a","b"])和空列表 [] 在提示。例:

In [115]: slice_list = make_df_slice_list(df)

DF index: foo has subindexes: ['a', 'b']
Enter a the indexes you'd like as a list: []
DF index: qux has subindexes: ['a', 'b']
Enter a the indexes you'd like as a list: ['a','b']

In [116]:slice_list
Out[116]: [['foo', 'qux', 'qux'], ['a', 'a', 'b']]

# Back to my original solution, but now passing the list:
slice_df = pd.DataFrame(index=slice_list)
column_slice = ['A','B']

slice_df.merge(df, left_index=True, right_index=True, how='inner').ix[:,column_slice]
Out[117]: 
              A         B
foo a -0.249547  0.056414
qux a  0.938710 -0.202213
    b  0.329136 -0.465999

4
2018-03-24 16:49





你的意思是?

import numpy as np
import pandas as pd
idx = pd.IndexSlice

index = [np.array(['foo', 'foo', 'qux', 'qux']),
         np.array(['a', 'b', 'a', 'b'])]
columns = ["A",  "B"]
df = pd.DataFrame(np.random.randn(4, 2), index=index, columns=columns)
print df

# 
la1 = lambda df: df.loc[idx['foo', :], idx['A':'B']]
la2 = lambda df: df.loc[idx['qux', :], idx['A':'B']]
laList = [la1, la2]

result = map(lambda la: la(df), laList)
print result[0]
print result[1]

              A         B
foo a  0.162138 -1.382822
    b -0.822986 -0.403766
qux a  0.191695 -1.125841
    b  0.669254 -0.704894
              A         B
foo a  0.162138 -1.382822
    b -0.822986 -0.403766
              A         B
qux a  0.191695 -1.125841
    b  0.669254 -0.704894

0
2018-04-10 02:43



不,不要害怕。 - bluprince13


你的意思是这个吗?

df.loc[idx['foo',:], :].loc[idx[:,'a'], :]

稍微更一般的形式,例如:

def multiindex_partial_row_slice(df, part_idx, criteria):
    slc = idx[tuple([slice(None) if i != part_idx else criteria 
                     for i in range(len(df.index.levels))])]
    return df.loc[slc, :]

multiindex_partial_row_slice(df, 1, slice('a','b'))

同样,您可以随时通过追加来缩小当前列集 .loc[:, columns] 到您当前切片的视图。


0
2018-04-15 09:10