我有很多变量,我的意图是在多次迭代中填充每个变量,而每个变量都需要不同的表达式来提取它们的值。下面的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时,创建一个数据帧,其中数据是值,索引是键。在您的情况下,您有元组键,因此使用的索引将是pd.MultiIndex
。此时,您有Var_2
、Var_3
和Var_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
您只需使用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
但是创建一个具有相同列的数据帧有点奇怪,因为它没有太多信息
尝试:
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
尝试:
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
我们也可以用pairs
创建一个DataFrame(这将创建一个有一行和MultiIndex列的DataFrame(,repeat
it(因为我们想重复同一行3次,所以我们使用Index.repeat
+reindex
重复3次(。然后用CCD_ 14+rename_axis
+CCD_;Var_ 1";正确命名和排序。然后CCD_ 17将以期望的形状传递数据。最后,我们可以使用sort_values
+reset_index
来获得与您构建的DataFrame相同的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'])