Python / Pandas仅在Value不为0时减去

问题描述 投票:1回答:2

我开始看起来像这样的数据,但有更多的行:

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
...

数据由前两列索引。我需要从-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中的位置,只使用以下代码减去当前列中的值不为零时列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:传递的项目数量错误9,位置意味着1”。

我认为减法导致问题,但我无法弄清楚如何改变它以使其工作。任何帮助将不胜感激。

提前致谢。

python-3.x pandas dataframe subtraction
2个回答
0
投票

方法1(非常快:大约比方法2快3倍) 1.选择相关的列 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

方法2(更易读) 1.找到条件大于0的部分。 2.选择相关的行 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执行元素乘法与另一个数据帧。


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)
© www.soinside.com 2019 - 2024. All rights reserved.