是否有更密集的方法来有条件地分离数据?

Is there a more dense method to conditionally separate data?

我想知道是否有更密集的方法来执行以下操作,这实际上是按行拆分列分隔的数据,并根据行的最终条目分为三个类别之一:

xi_test_0 = [xi_test_sc[i] for i in range(len(xi_test_sc)) if y_test[i] == 0]
xii_test_0 = [xii_test_sc[i] for i in range(len(xii_test_sc)) if y_test[i] == 0]
y_test_0 = [y_test[i] for i in range(len(y_test)) if y_test[i] == 0]

xi_test_1 = [xi_test_sc[i] for i in range(len(xi_test_sc)) if y_test[i] == 1]
xii_test_1 = [xii_test_sc[i] for i in range(len(xii_test_sc)) if y_test[i] == 1]
y_test_1 = [y_test[i] for i in range(len(y_test)) if y_test[i] == 1]

xi_test_2 = [xi_test_sc[i] for i in range(len(xi_test_sc)) if y_test[i] == 2]
xii_test_2 = [xii_test_sc[i] for i in range(len(xii_test_sc)) if y_test[i] == 2]
y_test_2 = [y_test[i] for i in range(len(y_test)) if y_test[i] == 2]```

为每个要中断的条件创建一组布尔数组:

split_index = {i: y_test == i for i in range(3)}

根据此布尔索引将您的数据分组。

xi_test_split = {i: xi_test_sc[idx, :] for i, idx in split_index.items()}
xii_test_split = {i: xii_test_sc[idx, :] for i, idx in split_index.items()}
y_test_split = {i: y_test[idx, :] for i, idx in split_index.items()}

xi_test_0xi_test_1 等都由一个仅在数字常量上有所不同的表达式进行初始化——所以首先要将它们转换成列表:

xi_test = [
    [xi_test_sc[i] for i in range(len(xi_test_sc)) if y_test[i] == j]
    for j in range(3)
]
xii_test = [
    [xii_test_sc[i] for i in range(len(xii_test_sc)) if y_test[i] == j] 
    for j in range(3)
]
y_test_n = [
    [y_test[i] for i in range(len(y_test)) if y_test[i] == j] 
    for j in range(3)
]

我们还可以通过 zipping 我们正在迭代的两个列表而不是使用 range:

来简化单个列表理解
xi_test = [
    [a for a, b in zip(xi_test_sc, y_test) if b == j]
    for j in range(3)
]
xii_test = [
    [a for a, b in zip(xii_test_sc, y_test) if b == j]
    for j in range(3)
]
y_test_n = [
    [a for a, b in zip(y_test, y_test) if b == j]
    for j in range(3)
]

现在我们要看的代码变少了,很容易看出它们也有一个值不同——所以让我们把整个东西变成一个字典:

test_data = {
    name: [[a for a, b in zip(sc_data, y_test) if b == j] for j in range(3)]
    for name, sc_data in (
        ('xi', xi_test_sc), ('xii', xii_test_sc), ('y', y_test)
    )
}

这与您的原始代码生成的数据相同,没有进行所有复制和粘贴操作。 xi_test_0 现在是 test_data['xi'][0]y_test_1 现在是 test_data['y'][1],等等。

或者,如果您更喜欢将每个列表分配给不同的命名变量,而不是在字典中创建名称键:

xi, xii, y = (
    [[a for a, b in zip(sc_data, y_test) if b == j] for j in range(3)] 
    for sc_data in (xi_test_sc, xii_test_sc, y_test)
)

如果这些都是 numpy 数组,你可以使用掩码:

xi_test_0 = xi_test_sc[y_test==0]
y_test_0  = y_test[y_test==0]

xi_test_1  = xi_test_sc[y_test== 1]
xii_test_1 = xii_test_sc[y_test == 1]

... and so on ...

或者,如果您希望结果是 0、1、2 中性数对应于您的 _0、_1、_2 变量名称后缀的二维矩阵:

mask = y_test == np.arange(3)[:,None]
xi_test_n  = xi_test_sc[mask]
xii_test_n = xii_test_sc[mask]
...