Python/Pandas 仅当值不为 0 时减去
Python/Pandas Subtract Only if Value is not 0
我从看起来像这样的数据开始,但行数更多:
Location Sample a b c d e f g h i
1 w 14.6 0 0 0 0 0 0 0 16.8
2 x 0 13.6 0 0 0 0 0 0 16.5
3 y 0 0 15.5 0 0 0 0 0 16.9
4 z 0 0 0 0 14.3 0 0 0 15.7
...
数据由前两列索引。我需要从 a - h 中的每个值中减去第 i 列中的值,并在每个原始列的数据框右侧添加一个新列。但是,如果第一列中有零,我希望它保持零而不是减去。例如,如果我的代码有效,我会将以下列添加到右侧的数据框中
Location Sample ... a2 b2 c2 d2 e2 f2 g2 h2
1 w ... -2.2 0 0 0 0 0 0 0
2 x ... 0 -2.9 0 0 0 0 0 0
3 y ... 0 0 -1.4 0 0 0 0 0
4 z ... 0 0 0 0 -1.4 0 0 0
...
如果当前列中的值不为零,我正在尝试使用 pandas 中的 where 仅减去第 i 列中的值,使用以下代码:
import pandas as pd
normalizer = i
columns = list(df.columns.values)
for column in columns:
if column == normalizer: continue
newcol = gene + "2"
df[newcol] = df.where(df[column] == 0,
df[column] - df[normalizer], axis = 0)
我正在使用 for 循环,因为列数不会始终相同,并且要减去的列将使用不同的数据集具有不同的名称。
我收到此错误:"ValueError: Wrong number of items passed 9, placement implies 1"。
我认为减法是导致问题的原因,但我不知道如何更改它才能使其正常工作。如有任何帮助,我们将不胜感激。
提前致谢。
使用 mask
+ fillna
df.iloc[:,2:-1]=df.iloc[:,2:-1].mask(df.iloc[:,2:-1]==0).sub(df['i'],0).fillna(0)
df
Out[116]:
Location Sample a b c d e f g h i
0 1 w -2.2 0.0 0.0 0.0 0.0 0.0 0.0 0.0 16.8
1 2 x 0.0 -2.9 0.0 0.0 0.0 0.0 0.0 0.0 16.5
2 3 y 0.0 0.0 -1.4 0.0 0.0 0.0 0.0 0.0 16.9
3 4 z 0.0 0.0 0.0 0.0 -1.4 0.0 0.0 0.0 15.7
更新
normalizer = ['i','Location','Sample']
df.loc[:,~df.columns.isin(normalizer)]=df.loc[:,~df.columns.isin(normalizer)].mask(df.loc[:,~df.columns.isin(normalizer)]==0).sub(df['i'],0).fillna(0)
方法 1(相当快:大约比方法 2 快 3 倍)
1. Select 相关栏目
2.做减法
3. 与在减法之前构建的 0、1 矩阵进行逐元素乘法。 (df_ref > 0) 中的每个元素如果最初为 0 则为 0,否则为 1。
ith_col = df["i"]
subdf = df.iloc[:, 2:-1] # a - h columns
df_temp = subdf.sub(ith_col, axis=0).multiply(subdf > 0).add(0)
df_temp.columns = ['a2', 'b2', 'c2', 'd2', 'e2', 'f2', 'g2', 'h2'] # rename columns
df_desired = pd.concat([df, df_temp], axis=1)
注意这个方法中,0是负数。因此,最后我们有一个额外的 add(0)
。是的,0 可以是负数。 :P
方法二(更具可读性)
1.找到大于0的有条件的部分
2. Select行是相关的
3. 减法
4.填写0。
ith_col = df["i"]
df[df > 0].iloc[:,2:-1].sub(ith_col, axis=0).fillna(0)
第二种方法和@Wen的回答很相似。归功于他:P
两种方法的速度比较(在Python 3和pandas 0.20上测试)
%timeit subdf.sub(ith_col, axis=0).multiply(subdf > 0).add(0)
688 µs ± 30.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit df[df > 0].iloc[:,2:-1].sub(ith_col, axis=0).fillna(0)
2.97 ms ± 248 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
参考:
DataFrame.multiply
与另一个数据框执行元素乘法。
我从看起来像这样的数据开始,但行数更多:
Location Sample a b c d e f g h i
1 w 14.6 0 0 0 0 0 0 0 16.8
2 x 0 13.6 0 0 0 0 0 0 16.5
3 y 0 0 15.5 0 0 0 0 0 16.9
4 z 0 0 0 0 14.3 0 0 0 15.7
...
数据由前两列索引。我需要从 a - h 中的每个值中减去第 i 列中的值,并在每个原始列的数据框右侧添加一个新列。但是,如果第一列中有零,我希望它保持零而不是减去。例如,如果我的代码有效,我会将以下列添加到右侧的数据框中
Location Sample ... a2 b2 c2 d2 e2 f2 g2 h2
1 w ... -2.2 0 0 0 0 0 0 0
2 x ... 0 -2.9 0 0 0 0 0 0
3 y ... 0 0 -1.4 0 0 0 0 0
4 z ... 0 0 0 0 -1.4 0 0 0
...
如果当前列中的值不为零,我正在尝试使用 pandas 中的 where 仅减去第 i 列中的值,使用以下代码:
import pandas as pd
normalizer = i
columns = list(df.columns.values)
for column in columns:
if column == normalizer: continue
newcol = gene + "2"
df[newcol] = df.where(df[column] == 0,
df[column] - df[normalizer], axis = 0)
我正在使用 for 循环,因为列数不会始终相同,并且要减去的列将使用不同的数据集具有不同的名称。
我收到此错误:"ValueError: Wrong number of items passed 9, placement implies 1"。
我认为减法是导致问题的原因,但我不知道如何更改它才能使其正常工作。如有任何帮助,我们将不胜感激。
提前致谢。
使用 mask
+ fillna
df.iloc[:,2:-1]=df.iloc[:,2:-1].mask(df.iloc[:,2:-1]==0).sub(df['i'],0).fillna(0)
df
Out[116]:
Location Sample a b c d e f g h i
0 1 w -2.2 0.0 0.0 0.0 0.0 0.0 0.0 0.0 16.8
1 2 x 0.0 -2.9 0.0 0.0 0.0 0.0 0.0 0.0 16.5
2 3 y 0.0 0.0 -1.4 0.0 0.0 0.0 0.0 0.0 16.9
3 4 z 0.0 0.0 0.0 0.0 -1.4 0.0 0.0 0.0 15.7
更新
normalizer = ['i','Location','Sample']
df.loc[:,~df.columns.isin(normalizer)]=df.loc[:,~df.columns.isin(normalizer)].mask(df.loc[:,~df.columns.isin(normalizer)]==0).sub(df['i'],0).fillna(0)
方法 1(相当快:大约比方法 2 快 3 倍)
1. Select 相关栏目
2.做减法
3. 与在减法之前构建的 0、1 矩阵进行逐元素乘法。 (df_ref > 0) 中的每个元素如果最初为 0 则为 0,否则为 1。
ith_col = df["i"]
subdf = df.iloc[:, 2:-1] # a - h columns
df_temp = subdf.sub(ith_col, axis=0).multiply(subdf > 0).add(0)
df_temp.columns = ['a2', 'b2', 'c2', 'd2', 'e2', 'f2', 'g2', 'h2'] # rename columns
df_desired = pd.concat([df, df_temp], axis=1)
注意这个方法中,0是负数。因此,最后我们有一个额外的 add(0)
。是的,0 可以是负数。 :P
方法二(更具可读性)
1.找到大于0的有条件的部分
2. Select行是相关的
3. 减法
4.填写0。
ith_col = df["i"]
df[df > 0].iloc[:,2:-1].sub(ith_col, axis=0).fillna(0)
第二种方法和@Wen的回答很相似。归功于他:P
两种方法的速度比较(在Python 3和pandas 0.20上测试)
%timeit subdf.sub(ith_col, axis=0).multiply(subdf > 0).add(0)
688 µs ± 30.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit df[df > 0].iloc[:,2:-1].sub(ith_col, axis=0).fillna(0)
2.97 ms ± 248 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
参考:
DataFrame.multiply
与另一个数据框执行元素乘法。