自定义算法来处理 DataFrame 中的负值
Custom algorithm to deal with negative values within a DataFrame
首先,我有一个如下所示的 DataFrame:
df = pd.DataFrame({'a': [25, 22, -2, 16, 10], 'b': [-5, 18, -2, 25, 48], 'c': [34, -12, 7, 8, 22],
'd': [10, 8, -2, -4, 12]})
目标:使用保留每列中负值影响的特定脚本或函数消除所有零。
我正在尝试开发一种方法来查看数据框,找到负值并取负值的绝对值并加一。本质上,这会将 DataFrame 中的每个负值替换为正值 1。
接下来,我想减去我在取负数的绝对值(加一)后计算的值,然后从下一行值(同一列内)中减去它。
另外:
在负值后面的值也是负数的情况下,我想对两个负值都做同样的操作,但是我想减去绝对值加一的总和,对于每个负数,并从下一个减去正排。如果在我想从之后的行中减去之后,修正后的负值之后的行值变得小于 1,直到负值消失并且它们之后的行都小于 1。
预期的输出将有望帮助理解我打算做什么:
expected_output = pd.DataFrame({'a': [25, 22, 1, 13, 10], 'b': [1, 12, 1, 22, 48],
'c': [34, 1, 1, 1, 22],'d': [10, 8, 1, 1, 4]})
我可以用负值的绝对值加一来代替负值,使用:
df[df < 0] = abs(df[df < 0] + 1)
我也知道我可以使用以下方法找到负值的位置:
neg_loc = df.loc[df['a'] < 0].index
现在我使用以下方法找到负值后的值:
row_after_neg = df['a'].iloc[neg_loc + 1]
最后,我可以将负值的绝对值加一添加到负值之后的行:
total = row_after_neg.add(abs(neg_loc + 1))
所以,我的问题是如何将它们拼接在一起,以便它遍历整个 DataFrame 并执行我指定的操作。
提前感谢您的 advice/help!
你的问题有点令人困惑,所以我希望我能解决所有的要求,如果没有,请在评论中告诉我。我选择使用 for 循环,因为您想进行逐行比较。如果速度是一个问题,我会避免使用 for 循环,看看你是否可以留在熊猫的架构中。
设置:
import pandas as pd
df = pd.DataFrame({'a': [25, 22, -2, 16, 10], 'b': [-5, 18, -2, 25, 48], 'c': [34, -12, 7, 8, 22],
'd': [10, 8, -2, -4, 12]})
创建一个具有 abs(负值)+ 1 和 0 的数据框版本以替换正值的 nans
:
pos_df = (abs(df[df < 0]) + 1).fillna(0)
For 循环从第二行开始遍历数据帧:
for index, row in df.iloc[1:,:].iterrows():
然后用正数据帧的前一行减去数据帧的行
df.loc[index] = row - pos_df.loc[index - 1]
然后您重新计算 pos_df
的行,因为您想要检查是否有任何数字变为负数。需要注意的是,我正在切换 df
数据帧而不是 pos_df
中的所有负值。
pos_df.loc[index][df.loc[index] < 0] = (abs(df.loc[index][df.loc[index] < 0]) + 1).fillna(0)
最后将所有负值更改为 1:
df[df < 0] = 1
完整代码如下:
import pandas as pd
df = pd.DataFrame({'a': [25, 22, -2, 16, 10], 'b': [-5, 18, -2, 25, 48], 'c': [34, -12, 7, 8, 22],
'd': [10, 8, -2, -4, 12]})
pos_df = (abs(df[df < 0]) + 1).fillna(0)
for index, row in df.iloc[1:,:].iterrows():
df.loc[index] = row - pos_df.loc[index - 1]
pos_df.loc[index][df.loc[index] < 0] = (abs(df.loc[index][df.loc[index] < 0]) + 1).fillna(0)
df[df < 0] = 1
最终输出为:
a b c d
0 25.0 1.0 34.0 10.0
1 22.0 12.0 1.0 8.0
2 1.0 1.0 1.0 1.0
3 13.0 22.0 1.0 1.0
4 10.0 48.0 22.0 4.0
希望对您有所帮助!
编辑:
所以代码:
pos_df.loc[index][df.loc[index] < 0] = (abs(df.loc[index][df.loc[index] < 0]) + 1).fillna(0)
是一个比较复杂的pandas表达式。一点上下文,在 Pandas 中有 series
和 dataframes
,您可以将 series
视为数据框的一列或一行。当您在数据框中执行条件 selection 时,数据框会保持其形状,不符合条件的值显示为 Nan
。使用系列,您只会获得满足条件的值。
这是一个例子:
df[df == 1]
series[series == 1]
a b c d
0 Nan Nan Nan Nan
1 Nan Nan 1.0 Nan
2 Nan Nan 1.0 1.0
3 Nan Nan 1.0 1.0
4 Nan Nan Nan Nan
c
1.0
1.0
1.0
因此,正如您在上面看到的,该系列的形状从 [5,1] 变为 [3,1]。现在回到代码。 pos_df.loc[index]
selects 我们感兴趣的行来自数据框,其中包含转换后的负数。如果您将其视为:
,可能更容易概念化
pos_s = pos_df.loc[index]
s = df.loc[index]
pos_s[s < 0] = (abs(s[s < 0]) + 1).fillna(0)
因此,正如您在上面看到的,这与您在问题中使用的表达式相同,但在 for 循环目前正在迭代的行上执行,而不是在整个数据帧上执行。在代码中:
(abs(s[s < 0]) + 1).fillna(0)
我正在查找数据框中所有曾经或已经变成负数的值并重新转换它们。然后我得到一个像这样的系列:
c
13
12
4
因为这是一个系列,您会注意到形状是 [3,1] 而不是预期的 [5,1]。所以为了避免弄乱数据框,我必须只替换负值。所以我使用代码:
pos_s[s < 0]
我正在 select 计算 df
行中的所有负数,所以输出是
[False, True, True, False, True]
然后我将此条件应用到 pos_df
的行到 select 第二个、第三个和第五个值并更新它们,以防任何最初的正值一旦减去就变成负值。
首先,我有一个如下所示的 DataFrame:
df = pd.DataFrame({'a': [25, 22, -2, 16, 10], 'b': [-5, 18, -2, 25, 48], 'c': [34, -12, 7, 8, 22],
'd': [10, 8, -2, -4, 12]})
目标:使用保留每列中负值影响的特定脚本或函数消除所有零。
我正在尝试开发一种方法来查看数据框,找到负值并取负值的绝对值并加一。本质上,这会将 DataFrame 中的每个负值替换为正值 1。
接下来,我想减去我在取负数的绝对值(加一)后计算的值,然后从下一行值(同一列内)中减去它。
另外: 在负值后面的值也是负数的情况下,我想对两个负值都做同样的操作,但是我想减去绝对值加一的总和,对于每个负数,并从下一个减去正排。如果在我想从之后的行中减去之后,修正后的负值之后的行值变得小于 1,直到负值消失并且它们之后的行都小于 1。
预期的输出将有望帮助理解我打算做什么:
expected_output = pd.DataFrame({'a': [25, 22, 1, 13, 10], 'b': [1, 12, 1, 22, 48],
'c': [34, 1, 1, 1, 22],'d': [10, 8, 1, 1, 4]})
我可以用负值的绝对值加一来代替负值,使用:
df[df < 0] = abs(df[df < 0] + 1)
我也知道我可以使用以下方法找到负值的位置:
neg_loc = df.loc[df['a'] < 0].index
现在我使用以下方法找到负值后的值:
row_after_neg = df['a'].iloc[neg_loc + 1]
最后,我可以将负值的绝对值加一添加到负值之后的行:
total = row_after_neg.add(abs(neg_loc + 1))
所以,我的问题是如何将它们拼接在一起,以便它遍历整个 DataFrame 并执行我指定的操作。
提前感谢您的 advice/help!
你的问题有点令人困惑,所以我希望我能解决所有的要求,如果没有,请在评论中告诉我。我选择使用 for 循环,因为您想进行逐行比较。如果速度是一个问题,我会避免使用 for 循环,看看你是否可以留在熊猫的架构中。
设置:
import pandas as pd
df = pd.DataFrame({'a': [25, 22, -2, 16, 10], 'b': [-5, 18, -2, 25, 48], 'c': [34, -12, 7, 8, 22],
'd': [10, 8, -2, -4, 12]})
创建一个具有 abs(负值)+ 1 和 0 的数据框版本以替换正值的 nans
:
pos_df = (abs(df[df < 0]) + 1).fillna(0)
For 循环从第二行开始遍历数据帧:
for index, row in df.iloc[1:,:].iterrows():
然后用正数据帧的前一行减去数据帧的行
df.loc[index] = row - pos_df.loc[index - 1]
然后您重新计算 pos_df
的行,因为您想要检查是否有任何数字变为负数。需要注意的是,我正在切换 df
数据帧而不是 pos_df
中的所有负值。
pos_df.loc[index][df.loc[index] < 0] = (abs(df.loc[index][df.loc[index] < 0]) + 1).fillna(0)
最后将所有负值更改为 1:
df[df < 0] = 1
完整代码如下:
import pandas as pd
df = pd.DataFrame({'a': [25, 22, -2, 16, 10], 'b': [-5, 18, -2, 25, 48], 'c': [34, -12, 7, 8, 22],
'd': [10, 8, -2, -4, 12]})
pos_df = (abs(df[df < 0]) + 1).fillna(0)
for index, row in df.iloc[1:,:].iterrows():
df.loc[index] = row - pos_df.loc[index - 1]
pos_df.loc[index][df.loc[index] < 0] = (abs(df.loc[index][df.loc[index] < 0]) + 1).fillna(0)
df[df < 0] = 1
最终输出为:
a b c d
0 25.0 1.0 34.0 10.0
1 22.0 12.0 1.0 8.0
2 1.0 1.0 1.0 1.0
3 13.0 22.0 1.0 1.0
4 10.0 48.0 22.0 4.0
希望对您有所帮助!
编辑:
所以代码:
pos_df.loc[index][df.loc[index] < 0] = (abs(df.loc[index][df.loc[index] < 0]) + 1).fillna(0)
是一个比较复杂的pandas表达式。一点上下文,在 Pandas 中有 series
和 dataframes
,您可以将 series
视为数据框的一列或一行。当您在数据框中执行条件 selection 时,数据框会保持其形状,不符合条件的值显示为 Nan
。使用系列,您只会获得满足条件的值。
这是一个例子:
df[df == 1]
series[series == 1]
a b c d
0 Nan Nan Nan Nan
1 Nan Nan 1.0 Nan
2 Nan Nan 1.0 1.0
3 Nan Nan 1.0 1.0
4 Nan Nan Nan Nan
c
1.0
1.0
1.0
因此,正如您在上面看到的,该系列的形状从 [5,1] 变为 [3,1]。现在回到代码。 pos_df.loc[index]
selects 我们感兴趣的行来自数据框,其中包含转换后的负数。如果您将其视为:
pos_s = pos_df.loc[index]
s = df.loc[index]
pos_s[s < 0] = (abs(s[s < 0]) + 1).fillna(0)
因此,正如您在上面看到的,这与您在问题中使用的表达式相同,但在 for 循环目前正在迭代的行上执行,而不是在整个数据帧上执行。在代码中:
(abs(s[s < 0]) + 1).fillna(0)
我正在查找数据框中所有曾经或已经变成负数的值并重新转换它们。然后我得到一个像这样的系列:
c
13
12
4
因为这是一个系列,您会注意到形状是 [3,1] 而不是预期的 [5,1]。所以为了避免弄乱数据框,我必须只替换负值。所以我使用代码:
pos_s[s < 0]
我正在 select 计算 df
行中的所有负数,所以输出是
[False, True, True, False, True]
然后我将此条件应用到 pos_df
的行到 select 第二个、第三个和第五个值并更新它们,以防任何最初的正值一旦减去就变成负值。