将 Dataframe 列值转换为公共小数位

Convert Dataframe column values to common decimal place

我有一个 Pandas 数据框,看起来像这样。

CustId CustName  Price_1  Priceqty1  Price_2  Priceqty2  Price_3  Priceqty3  Price_4   Price_5
5015      Axn     315.12      1        374       1        126.32       3     167.8765     
5015      Axn     75.36       3      190.19      7        33.16        1     190.19      88
5015      Axn     123         5                  4        18.07        2      0.073      12
7315      Bxy     12.0        4      22.345      3        77.89        1     345.0       3344
7315      Bxy     987.90      7      34.06       4        90.09        3     876.34      908.76
3283      Cxz     123.34      8      55.78       7        12           9     878.09      98.456
3283      Cxz     178.90      7       88         8        0.09         0                 987.56

我有 5 个不同的价格列,它们具有不同的值和不同的小数位。为了让最终用户更好地理解,我需要将所有价格列值转换为通用小数位。

要转换我需要遵循一定的规则: 1.conversion 应该分别为每个客户 ID 完成。 2.Common 小数位将由具有最大小数位的价格列值确定。

让我们以 CustId 5015 为例

CustId CustName  Price_1  Priceqty1  Price_2  Priceqty2  Price_3  Priceqty3  Price_4   Price_5
5015      Axn     315.12      1        374       1        126.32       3     167.8765     
5015      Axn     75.36       3      190.19      7        33.16        1     190.19      88
5015      Axn     123         5                  4        18.07        2      0.073      12

如果你看到你可以找到 Price_4 列的第一行,这里的值为 167.8765,小数位是 4 。如果您检查 Custid 5015 的所有价格列值,与其他价格列值相比,小数位 4 是最大的。因为 4 是最大的,所以我需要将 custid 5015 的每个价格列值转换为小数点后 4 位。

转换后应该是这样的。

CustId CustName  Price_1  Priceqty1  Price_2   Priceqty2  Price_3  Priceqty3  Price_4   Price_5
5015      Axn     315.1200      1    374.0000      1      126.3200     3     167.8765     
5015      Axn     75.3600       3    190.1900      7      33.1600      1     190.1900    88
5015      Axn     123.0000      5                  4      18.0700      2     0.0730      12

与 custid 5015 类似,custid 7315 的最大十进制值为 3

CustId CustName  Price_1  Priceqty1  Price_2  Priceqty2  Price_3  Priceqty3  Price_4    Price_5
7315      Bxy    12.000        4      22.345      3        77.890        1     345.000       3344.000
7315      Bxy    987.900      7      34.060       4        90.090        3     876.340      908.760

空白值只能为空白。

我需要为每个 custid 执行此操作,有 800 多个不同的客户 ID。最有效的方法是什么?

您可以先计算数字的整数和小数部分长度,然后取最大值:

lengths = (df.filter(like='Price_')
             .stack().astype(str).dropna()
             .str.split('.', expand=True).astype(str)
             .apply(lambda c: c.str.len())
             .max()
            )

输出:

0    4  # this is the integer part
1    4  # this is the decimal part

然后,如果您不想更改数据而只想打印数据帧:

integer, decimal = lengths.values
total = integer+decimal+1
custom_format = '{:%s.%sf}' % (total,decimal)
pd.options.display.float_format = custom_format.format
print(df.fillna(''))

输出:

   CustId CustName   Price_1  Priceqty1   Price_2  Priceqty2   Price_3  Priceqty3   Price_4   Price_5
0    5015      Axn  315.1200          1  374.0000     1.0000  126.3200     3.0000  167.8765          
1    5015      Axn   75.3600          3  190.1900     7.0000   33.1600     1.0000  190.1900   88.0000
2    5015      Axn  123.0000          5    4.0000    18.0700    2.0000     0.0730   12.0000          
3    7315      Bxy   12.0000          4   22.3450     3.0000   77.8900     1.0000  345.0000 3344.0000
4    7315      Bxy  987.9000          7   34.0600     4.0000   90.0900     3.0000  876.3400  908.7600
5    3283      Cxz  123.3400          8   55.7800     7.0000   12.0000     9.0000  878.0900   98.4560
6    3283      Cxz  178.9000          7   88.0000     8.0000    0.0900     0.0000  987.5600          
df = df.fillna('')
m = df.filter(regex='Price_').astype(str).applymap(lambda x: len(x.split('.')[1]) if x else 0).max().max()
pd.options.display.float_format = ('{:,.' + str(m) + 'f}').format # based on 
print(df)

打印:

   CustId CustName  Price_1  Priceqty1  ...  Price_3  Priceqty3  Price_4    Price_5
0    5015      Axn 315.1200          1  ... 126.3200          3 167.8764           
1    5015      Axn  75.3600          3  ...  33.1600          1 190.1900    88.0000
2    5015      Axn 123.0000          5  ...  18.0700          2   0.0730    12.0000
3    7315      Bxy  12.0000          4  ...  77.8900          1 345.0000 3,344.0000
4    7315      Bxy 987.9000          7  ...  90.0900          3 876.3400   908.7600
5    3283      Cxz 123.3400          8  ...  12.0000          9 878.0900    98.4560
6    3283      Cxz 178.9000          7  ...   0.0900          0            987.5600

[7 rows x 10 columns]

每组使用自定义函数:

def f(x):
    #get string with maximal values after '.'
    a = max([str(y).split('.')[1] for y in np.ravel(x) if pd.notna(y)], key=len)
    #set format of floats
    return x.applymap(lambda x:  f'{x:.{len(a)}f}').replace('nan','')

df1 = df.filter(like='Price_')
df[df1.columns] = df1.groupby(df['CustId']).apply(f)
print (df)
   CustId CustName   Price_1  Priceqty1   Price_2  Priceqty2   Price_3  \
0    5015      Axn  315.1200          1  374.0000       1.00  126.3200   
1    5015      Axn   75.3600          3  190.1900       7.00   33.1600   
2    5015      Axn  123.0000          5    4.0000      18.07    2.0000   
3    7315      Bxy    12.000          4    22.345       3.00    77.890   
4    7315      Bxy   987.900          7    34.060       4.00    90.090   
5    3283      Cxz   123.340          8    55.780       7.00    12.000   
6    3283      Cxz   178.900          7    88.000       8.00     0.090   

   Priceqty3   Price_4   Price_5  
0      3.000  167.8765            
1      1.000  190.1900   88.0000  
2      0.073   12.0000            
3      1.000   345.000  3344.000  
4      3.000   876.340   908.760  
5      9.000   878.090    98.456  
6      0.000   987.560