如何将公式应用于数据框熊猫中的所有列

时间:2020-04-11 23:47:35

标签: python pandas

我有以下数据框:

import pandas as pd
data = {'MA1': [ float("nan"),  float("nan"),      -1,   1],
        'MA2': [ float("nan"),            -1,       0,   0],
        'MA3': [            0,             0,       1,  -1]}
df_input = pd.DataFrame(data, columns=['MA1', 'MA2', 'MA3'])

enter image description here

我的目标是对于每列,如果第一个非nan和非零值是-1,则将其设置为0。

说明:

仅当第一个非0和non nan值为-1时,目标才设置为0。如果它是1或其他任何值,则将其保留在那里。

enter image description here

最快的方法是什么?

4 个答案:

答案 0 :(得分:3)

您可以遍历各列,并在第一个有效值为DataFrame.loc时使用-1分配0:

dft = df_input.replace(0, np.NaN)

for col in df_input.columns:
    idxmin = dft[col].idxmin()
    if df_input.loc[idxmin, col] == -1:
        df_input.loc[idxmin, col] = 0

   MA1  MA2  MA3
0  NaN  NaN    0
1  NaN  0.0    0
2  0.0  0.0    1
3  1.0  0.0    0

或者通过使用DataFrame.idxmin来提高效率,因此我们不必为循环中的每个迭代调用Series.idxmin

dft = df_input.replace(0, np.NaN).idxmin()

for col, idx in dft.iteritems():
    if df_input.loc[idx, col] == -1:
        df_input.loc[idx, col] = 0

   MA1  MA2  MA3
0  NaN  NaN    0
1  NaN  0.0    0
2  0.0  0.0    1
3  1.0  0.0    0

答案 1 :(得分:1)

在使用python的一年结束时,我试图更好地实现性能更高的解决方案,因此我想我将测试我的答案相对于其他答案的性能(意识到我的答案将是最慢的-从我创建的数据框中 ,它的速度比最佳答案慢50,000x(哇!)。另外,这是一篇有关熊猫和表演的好文章:https://engineering.upside.com/a-beginners-guide-to-optimizing-pandas-code-for-speed-c09ef2c6a4d6

我的传统慢循环方法将3列循环了将近100,000次(数据帧的长度),而最佳答案idx.min()识别了相关行时又循环了3列,因此不必循环通过它们全部。

这里是我用来测试@Erfan和@DerekO的具有100,000行和4列的数据框:

df_input = pd.DataFrame(np.random.randint(0, 10, size=(100000,4)).astype(float), columns=list('ABCD'))
df_input.iloc[99998:, 0:4] = -1

我的回答(最慢)2.78 s ± 269 ms per loop

for col in df_input.columns:
    for row in range(len(df_input.index)):
        if df_input.loc[row, col] == -1:
            df_input.loc[row, col] = 0
            break    
df_input

Derek O的答案#1:283 ms ± 13.2 ms per loop比我的答案快10倍!

Erfan的答案#1:2.73 ms ± 135 µs per loop比我的答案快1000倍!

Erfan的答案2:54.8 µs ± 5.65 µs per loop比我的答案快50,000倍!

答案 2 :(得分:0)

将自定义函数应用于每列。自定义函数遍历该列的值以查找第一个非nan非零值,然后返回新列。

import numpy as np
import pandas as pd

def set_column(col_values):
    for index, value in enumerate(col_values):
        if value != 0 and not np.isnan(value):
            if value == -1:
                col_values[index] = 0
                return col_values
            else:
                return col_values

data = {'MA1': [ float("nan"),  float("nan"),      -1,   1],
        'MA2': [ float("nan"),            -1,       0,   0],
        'MA3': [            0,             0,       1,   0]}

df_input = pd.DataFrame(data, columns=['MA1', 'MA2', 'MA3'])
df_output = df_input.copy().apply(lambda x: set_column(x), axis = 0)

输出:

>>> df_output
   MA1  MA2  MA3
0  NaN  NaN    0
1  NaN  0.0    0
2  0.0  0.0    1
3  1.0  0.0    0

答案 3 :(得分:0)

我对@Erfan的答案进行了修改。

正如我在 Update 编辑中所解释的,我只想在第一个非零和非nan值为-1时将其设置为零。如果还有其他内容,请不要对该列做任何事情。

df_min = df_input(0, np.NaN).idxmin()
df_max = df_input(0, np.NaN).idxmax()
for col, idx in df_min.iteritems():
    if df_input[idx, col] == -1 and idx < df_max[col]:
        df_input[idx, col] = 0