在每次迭代中使用 pandas 填充多个变量

Populating multiple variables in each iteration with pandas

我有许多变量,我的目的是在多次迭代中填充每个变量,而每个变量都需要不同的表达式才能提取它们的值。大致相当于我正在尝试做的是以下 for 循环。

pairs = {('Ams', 'Rot') : 10, ('Del', 'Utr') : 12, ('Ams', 'Utr') : 14, ('Del', 'Rot') : 16}

var_1 = []
var_2 = []
var_3 = []
var_4 = []

for i in range(3):
    for (j, k) in pairs:
        var_1.append(i)
        var_2.append(j)
        var_3.append(k)
        var_4.append(pairs[(j, k)])

df = {'Var_1' : var_1, 'Var_2' : var_2, 'Var_3' : var_3, 'Var_4' : var_4}
df = pd.DataFrame(df)
print(df)

我想要的输出:

    Var_1 Var_2 Var_3  Var_4
0       0   Ams   Rot     10
1       0   Del   Utr     12
2       0   Ams   Utr     14
3       0   Del   Rot     16
4       1   Ams   Rot     10
5       1   Del   Utr     12
6       1   Ams   Utr     14
7       1   Del   Rot     16
8       2   Ams   Rot     10
9       2   Del   Utr     12
10      2   Ams   Utr     14
11      2   Del   Rot     16

但是,我很想知道是否有更有效的方法来做到这一点,尤其是 pandas。最后,我想创建以下字典的 pandas DataFrame。

您可以使用 dict-comprehension 轻松设置

names = ['var_1', 'var_2', 'var_3', 'var_4']
values = {n: range(3) for n in names}
df = pd.DataFrame(values)
   var_1  var_2  var_3  var_4
0      0      0      0      0
1      1      1      1      1
2      2      2      2      2

但是创建具有相同列的数据框有点奇怪,没有太多信息

我们也可以用pairs创建一个DataFrame(这将创建一个只有一行和MultiIndex列的DataFrame),repeat它(因为我们想重复同一行3次,我们使用 Index.repeat + reindex 重复 3 次)。然后我们使用 reset_index + rename_axis + reset_index 来正确命名和排序“Var_1”。然后 melt 将以所需的形状传送数据。最后,我们可以使用 sort_values + reset_index 来获得与您构建的相同的 DataFrame。

tmp = pd.DataFrame(pairs, index=[0])
out = (tmp.reindex(tmp.index.repeat(3))
       .reset_index(drop=True)
       .rename_axis('Var_1')
       .reset_index()
       .melt(id_vars=['Var_1'], var_name=['Var_2', 'Var_3'], value_name='Var_4')
       .sort_values(by='Var_1')
       .reset_index(drop=True))

输出:

    Var_1 Var_2 Var_3  Var_4
0       0   Ams   Rot     10
1       0   Del   Utr     12
2       0   Ams   Utr     14
3       0   Del   Rot     16
4       1   Ams   Rot     10
5       1   Del   Utr     12
6       1   Ams   Utr     14
7       1   Del   Rot     16
8       2   Ams   Rot     10
9       2   Del   Utr     12
10      2   Ams   Utr     14
11      2   Del   Rot     16

或者您可以编写一个列表理解并构建一个带有列表的 DataFrame。这与您已有的非常相似。唯一的区别是它不是构建 4 个单独的列表,而是构建一个列表。

tmp = [[i, j, k, v] for i in range(3) for (j, k), v in pairs.items()]
df = pd.DataFrame(tmp, columns=['Var_1', 'Var_2', 'Var_3', 'Var_4'])

尝试:

df = (pd.DataFrame({n: pd.Series(pairs) for n in range(3)})
        .stack()
        .rename_axis(["Var_2", "Var_3", "Var_1"])
        .rename("Var_4")
        .reset_index()
        .sort_values("Var_1", ignore_index=True)
        .sort_index(axis=1)
        )

>>> df

   Var_1 Var_2 Var_3  Var_4
0       0   Ams   Rot     10
1       0   Del   Utr     12
2       0   Ams   Utr     14
3       0   Del   Rot     16
4       1   Ams   Rot     10
5       1   Del   Utr     12
6       1   Ams   Utr     14
7       1   Del   Rot     16
8       2   Ams   Rot     10
9       2   Del   Utr     12
10      2   Ams   Utr     14
11      2   Del   Rot     16

您可以使用基于索引的解决方案:

当你有一个字典时,创建一个数据框,其中数据是值,索引是键。在您的情况下,您有元组键,因此使用索引将是 pd.MultiIndex。此时你有 Var_2Var_3Var_4.

棘手的部分是从这个数据帧生成 Var_1。重复索引 3 次并重新索引数据框。所有值都是重复的。所以你有 3 x (Ams, Rot, 10), 3 x (Del, Utr, 12) 等等。现在,如果将这些重复的行组合在一起,则可以使用 cumcount 创建一个 ID(0 -> 第一个实例,1 -> 第二个实例,...)。最后按索引 (Var_1) 对数据帧进行排序并重置它以获得预期结果。

# Part 1: create Var_2, Var_3 and Var_4
mi = pd.MultiIndex.from_tuples(pairs.keys(), names=['Var_2', 'Var_3'])
df = pd.DataFrame({'Var_4': pairs.values()}, index=mi).reset_index()

# Part 2: create Var_1
df = df.reindex(df.index.repeat(3))
df = df.set_index(df.groupby(df.columns.tolist()).cumcount().rename('Var_1')) \
       .sort_index().reset_index()

输出:

>>> df
    Var_1 Var_2 Var_3  Var_4
0       0   Ams   Rot     10
1       0   Del   Utr     12
2       0   Ams   Utr     14
3       0   Del   Rot     16
4       1   Ams   Rot     10
5       1   Del   Utr     12
6       1   Ams   Utr     14
7       1   Del   Rot     16
8       2   Ams   Rot     10
9       2   Del   Utr     12
10      2   Ams   Utr     14
11      2   Del   Rot     16

尝试:

df = pd.concat([pd.Series(pairs, name='Var_4').to_frame()]*3, keys=range(3),
               names=['Var_1', 'Var_2', 'Var_3']).reset_index()

输出:

    Var_1 Var_2 Var_3  Var_4
0       0   Ams   Rot     10
1       0   Del   Utr     12
2       0   Ams   Utr     14
3       0   Del   Rot     16
4       1   Ams   Rot     10
5       1   Del   Utr     12
6       1   Ams   Utr     14
7       1   Del   Rot     16
8       2   Ams   Rot     10
9       2   Del   Utr     12
10      2   Ams   Utr     14
11      2   Del   Rot     16