我开始看起来像这样的数据,但有更多的行:
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”。
我认为减法导致问题,但我无法弄清楚如何改变它以使其工作。任何帮助将不胜感激。
提前致谢。
方法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
执行元素乘法与另一个数据帧。
使用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)