将值替换为其在总行中的百分比

时间:2019-04-15 09:55:48

标签: python pandas

用行中的百分比替换某些列中的值最直接的方法是什么?

示例:

从此

enter image description here

对此

enter image description here

我尝试了以下代码:

cols=['h1', 'h2', 'h3', 'hn']
df[cols]=df[cols]/df['sum']

但这会返回错误:

  

ValueError:列的长度必须与键的长度相同。

此外,我认为这不是最好的方法,因为我的列可能比4多得多。

3 个答案:

答案 0 :(得分:2)

DataFrame.div与指定axis=0一起使用:

cols=['h1', 'h2', 'h3', 'hn']
df[cols]=df[cols].div(df['sum'], axis=0)

如果sum是最后一列,则可以使用:

df.iloc[:, :-1]=df.iloc[:, :-1].div(df['sum'], axis=0)

示例

df = pd.DataFrame({
         'h1':[4,5,4,5,5,4],
         'h2':[7,8,9,4,2,3],
         'h3':[1,3,5,7,1,0],
         'hn':[4,5,4,5,5,4],
})
df['sum'] = df.sum(axis=1)

df.iloc[:, :-1] = df.iloc[:, :-1].div(df['sum'], axis=0)
print (df)
         h1        h2        h3        hn  sum
0  0.250000  0.437500  0.062500  0.250000   16
1  0.238095  0.380952  0.142857  0.238095   21
2  0.181818  0.409091  0.227273  0.181818   22
3  0.238095  0.190476  0.333333  0.238095   21
4  0.384615  0.153846  0.076923  0.384615   13
5  0.363636  0.272727  0.000000  0.363636   11

性能

np.random.seed(2019)

N = 10000
df = pd.DataFrame(np.random.randint(100, size=(N, 20))).add_prefix('h')
df['sum'] = df.sum(axis=1)
print (df)

In [220]: %%timeit
     ...: df.iloc[:, :-1]=df.iloc[:, :-1].div(df['sum'], axis=0)
     ...: 
8.03 ms ± 1.05 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)
C:\Anaconda\lib\site-packages\spyder\widgets\variableexplorer\utils.py:410: FutureWarning: 'summary' is deprecated and will be removed in a future version.
  display = value.summary()

In [221]: %%timeit
     ...: for col in df.columns[:-1]:
     ...:     df[col] /= df["sum"]
     ...: 
9.46 ms ± 168 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
C:\Anaconda\lib\site-packages\spyder\widgets\variableexplorer\utils.py:410: FutureWarning: 'summary' is deprecated and will be removed in a future version.
  display = value.summary()

In [222]: %%timeit
     ...: df.iloc[:,:-1] = df.iloc[:,:-1].apply(lambda x: x/sum(x), axis=1)
     ...: 
2.51 s ± 194 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
C:\Anaconda\lib\site-packages\spyder\widgets\variableexplorer\utils.py:410: FutureWarning: 'summary' is deprecated and will be removed in a future version.
  display = value.summary()

答案 1 :(得分:2)

也许更具可读性:

for col in df.columns[:-1]:
    df[col] /= df["sum"]

答案 2 :(得分:0)

另一种解决方案:

import pandas as pd

df = pd.DataFrame({
         'h1':[56,4,4,203],
         'h2':[89,67,3,4],
         'h3':[45,23,6,46],
         'hn':[32,44,78,78],
         'sum':[222,138,91,331],
})


df.iloc[:,:-1] = df.iloc[:,:-1].apply(lambda x: x/sum(x), axis=1)

您会得到:

    h1            h2          h3          hn        sum
0   0.252252    0.400901    0.202703    0.144144    222
1   0.028986    0.485507    0.166667    0.318841    138
2   0.043956    0.032967    0.065934    0.857143    91
3   0.613293    0.012085    0.138973    0.235650    331

请注意,此解决方案比jezrael的解决方案要慢得多。

%timeit df.iloc[:,:-1] = df.iloc[:,:-1].apply(lambda x: x/sum(x), axis=1)
%timeit df.iloc[:, :-1]=df.iloc[:, :-1].div(df['sum'], axis=0)

在普通笔记本电脑上,它可以给我:

3.33 ms ± 130 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
1.27 ms ± 1.82 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

慢了将近三倍。