我的数据框中有8列,值的范围可以从1到99。我试图创建其他列,例如'1_observed','2_observed','3_observed'...'99_observed' ,具体取决于该观察结果中是否出现了这些数字。
我正在运行的代码可以工作,但是由于我在一个循环中运行一个循环,所以速度很慢。
for index in df[observed_nos].index:
for num in range(1,100):
if num in df[observed_nos].iloc[index].values:
df[f'{num}_observed'][index] = '1'
else:
df[f'{num}_observed'][index] = '0'
我对熊猫没有丰富的经验,有没有办法使它运行更快/并行化呢?
编辑: 示例数据帧如下:
data = [[12,14,33,45,22,33,86,56],
[78,12,52,1,99,22,4,19],
[15,11,7,23,30,19,63,71],
[2,14,52,36,17,95,8,39],
[1,4,31,42,72,23,67,15],
[92,28,32,52,77,19,55,10],
[42,16,64,25,92,11,26,36],
[12,21,38,17,90,32,41,74],
]
df = pd.DataFrame(data, columns =['N1','N2','N3','N4','N5','N6','N7','N8'])
这将导致以下df
. N1 N2 N3 N4 N5 N6 N7 N8
0 12 14 33 45 22 33 86 56
1 78 12 52 1 99 22 4 19
2 15 11 7 23 30 19 63 71
3 2 14 52 36 17 95 8 39
4 1 4 31 42 72 23 67 15
5 92 28 32 52 77 19 55 10
6 42 16 64 25 92 11 26 36
7 12 21 38 17 90 32 41 74
我想要得到的输出如下:
N1 N2 N3 N4 N5 N6 N7 N8 1_ 2_ 3_ 4_ 5_ 6_ 7_ 8_ 9_
0 12 14 33 45 22 33 86 56 0 0 0 0 0 0 0 0 0
1 78 12 52 1 99 22 4 19 1 0 0 1 0 0 0 0 0
2 15 11 7 23 30 19 63 71 0 0 0 0 0 0 1 0 0
3 2 14 52 36 17 95 8 39 0 1 0 0 0 0 0 1 0
4 1 4 31 42 72 23 67 15 1 0 0 1 0 0 0 0 0
5 92 28 32 52 77 19 55 10 0 0 0 0 0 0 0 0 0
6 42 16 64 25 92 11 26 36 0 0 0 0 0 0 0 0 0
7 12 21 38 17 90 32 41 74 0 0 0 0 0 0 0 0 0
(我已将上面的示例删节了,仅检查数字1-9的出现,以便于查看)
答案 0 :(得分:1)
我和熊猫玩了一会儿,发现了另一个可能适合您的解决方案。尽管它没有提供0和1,但是提供了Trua和False(您可能需要修改数据以满足您的需要)。
此外,您可能想检查一下这段代码实际上是否比您的代码快:
rand = np.random.RandomState(42)
items = rand.randint(1, 100, 800).reshape((100, 8))
df = pd.DataFrame(items)
for n in range(1, 100):
df[f'{n}_observed'] = df[df == n].any(axis=1)
print(df)
希望这个建议对您有帮助!
答案 1 :(得分:1)
如果数字为正数,则可以将它们视为2D映射网格上的索引。因此,使用布尔网格数组,将给定值用作列索引,对于输入数据帧的每一行,使用相同的行索引。现在,使用这些行索引和列索引,在其中分配True
值。当以int
数组查看时,该网格也将是您的最终数组。因此,实现看起来像这样-
def presence_df(df, start=1, stop=99, str_postfix='_'):
c = df.to_numpy()
n = len(c)
id_ar = np.zeros((n,stop+1), dtype=bool)
id_ar[np.arange(n)[:,None],c] = 1
df1 = pd.DataFrame(id_ar[:,start:stop+1].view('i1'))
df1.columns = [str(i) + str_postfix for i in range(start,stop+1)]
df_out = pd.concat([df,df1],axis=1)
return df_out
样品运行-
In [41]: np.random.seed(0)
...: df = pd.DataFrame(np.random.randint(1,10,(8,10)))
In [42]: presence_df(df,start=1, stop=9)
Out[42]:
0 1 2 3 4 5 6 7 8 9 1_ 2_ 3_ 4_ 5_ 6_ 7_ 8_ 9_
0 6 1 4 4 8 4 6 3 5 8 1 0 1 1 1 1 0 1 0
1 7 9 9 2 7 8 8 9 2 6 0 1 0 0 0 1 1 1 1
2 9 5 4 1 4 6 1 3 4 9 1 0 1 1 1 1 0 0 1
3 2 4 4 4 8 1 2 1 5 8 1 1 0 1 1 0 0 1 0
4 4 3 8 3 1 1 5 6 6 7 1 0 1 1 1 1 1 1 0
5 9 5 2 5 9 2 2 8 4 7 0 1 0 1 1 0 1 1 1
6 8 3 1 4 6 5 5 7 5 5 1 0 1 1 1 1 1 1 0
7 4 5 5 9 5 4 8 6 6 1 1 0 0 1 1 1 0 1 1
给定样本数据和较大样本的时间-
In [17]: data = [[12,14,33,45,22,33,86,56],
...: [78,12,52,1,99,22,4,19],
...: [15,11,7,23,30,19,63,71],
...: [2,14,52,36,17,95,8,39],
...: [1,4,31,42,72,23,67,15],
...: [92,28,32,52,77,19,55,10],
...: [42,16,64,25,92,11,26,36],
...: [12,21,38,17,90,32,41,74],
...: ]
...: df = pd.DataFrame(data, columns =['N1','N2','N3','N4','N5','N6','N7','N8'])
In [18]: %timeit presence_df(df)
1000 loops, best of 3: 575 µs per loop
In [19]: df = pd.DataFrame(np.random.randint(1,100,(1000,1000)))
In [20]: %timeit presence_df(df)
100 loops, best of 3: 8.86 ms per loop