Pandas:追加行的副本,仅更改多个列中大于拆分仓位值所允许的最大值的值

2024-06-26 14:28:55 发布

您现在位置:Python中文网/ 问答频道 /正文

问题:我有一个数据框,需要根据特定列的值进行修改。如果任何列值的值大于允许的最大值,则将根据分布到大小相等的存储箱中创建新行(在数据值和允许的最大值之间进行整数除法)

表格和说明:

原创:

^{tb1}$

必需:

括号中的索引值指原始索引值

^{tb2}$

因为原始索引=2,所以Data1=10大于允许的最大值=8。如上表所示,该行已分为两行

尝试:我能够找到那些值大于允许的最大值和要插入的行数的列。但我有一个困惑,如果两列的值都大于最大允许值(如index=3),这种方法是否有效。这些值指示要为特定列的每个索引值插入多少行

^{tb3}$

Tags: 数据方法index整数表格括号原创data1
2条回答

假设您愿意逐行处理数据帧,则可以在while循环中执行最大值检查,并用新行填充新数据帧

import pandas as pd
df = pd.DataFrame({"Index" : [1, 2, 3], "Data 1" : [1,10,7], "Data 2" : [2,5,12], "Max_Allowed" : [3,8,5]})
print(df)
# create a new data frame that we can populate with rows of data
dfz = pd.DataFrame(columns=("Index", "Data 1","Data 2","Max_Allowed"))

iz = 0
for(_, col1, col2, col3, col4) in df.itertuples(name=None):
    
    if col2<=col4 and col3<=col4:             
        dfz.loc[iz] = [str(iz+1)+"("+str(col1)+")", col2, col3, col4]
        iz += 1
    else:
        iz_orig = iz  # keep the index we are at currently
        while col2>0 or col3>0:
            
            if col2>col4:   # check if more than maximum value for Data 1
                col2p=col4
                col2 -= col4  # minus the maximum value from current value
            else:
                col2p=col2
                col2 = 0   # set the value to zero
                
            if col3>col4:  # check if more than maximum value for Data 2
                col3p=col4
                col3 -= col4
            else:
                col3p=col3
                col3 = 0

            if iz_orig == iz:
                # enter with the original Index in parenthesis
                dfz.loc[iz] = [str(iz+1)+"("+str(col1)+")", col2p, col3p, col4]
            else:
                # enter row with just the new Index
                dfz.loc[iz] = [str(iz+1), col2p, col3p, col4]
                
            iz += 1

print(dfz)

让我们按照以下步骤进行操作:

步骤1:分割值的准备:

定义自定义lambda函数,将Data 1Data 2转换为值列表,如果大于该值,则使用Max. Allowed进行拆分。将展开的列表保存在两个新列中Data 1xData 2x

f = lambda x, y, z: [z] * (x // z) + [x % z] + [0] * (max(x//z, y//z) - x//z)

df['Data 1x'] = df.apply(lambda x: f(x['Data 1'], x['Data 2'], x['Max. Allowed'])  , axis=1)
df['Data 2x'] = df.apply(lambda x: f(x['Data 2'], x['Data 1'], x['Max. Allowed'])  , axis=1)

lambda函数用于将0添加到列表中,以使同一行列表中的元素数具有相同的长度

中间结果:

print(df)

   Index  Data 1  Data 2  Max. Allowed    Data 1x    Data 2x
0      1       1       2             3        [1]        [2]
1      2      10       5             8     [8, 2]     [5, 0]
2      3       7      12             5  [5, 2, 0]  [5, 5, 2]

步骤2:将拆分值分解为单独的行:

案例1:如果您的Pandas版本为1.3或更高版本

我们使用^{}分解2个新列:(分解多个列的这部分功能需要1.3版或更高版本)

df = df.explode(['Data 1x', 'Data 2x'])

案例2:对于低于1.3的Pandas版本,请尝试以下爆炸方式:

df = df.apply(pd.Series.explode)

案例3:如果上述两种分解方法在您的编程环境中不起作用,请使用:

df_exp = df.explode('Data 1x')[['Index', 'Data 1', 'Data 2', 'Max. Allowed']].reset_index(drop=True)
df_1x = df.explode('Data 1x')[['Data 1x']].reset_index(drop=True)
df_2x = df.explode('Data 2x')[['Data 2x']].reset_index(drop=True)

df = df_exp.join([df_1x, df_2x])

结果:

print(df)

   Index  Data 1  Data 2  Max. Allowed Data 1x Data 2x
0      1       1       2             3       1       2
1      2      10       5             8       8       5
1      2      10       5             8       2       0
2      3       7      12             5       5       5
2      3       7      12             5       2       5
2      3       7      12             5       0       2

步骤3:格式化为所需输出:

# select and rename columns
df = (df[['Index', 'Data 1x',  'Data 2x', 'Max. Allowed']]
        .rename({'Data 1x': 'Data 1', 'Data 2x': 'Data 2'}, axis=1)
        .reset_index(drop=True)
     )

# reset the `Index` values
df['Index'] = df.index + 1  

最终结果:

print(df)


   Index Data 1 Data 2  Max. Allowed
0      1      1      2             3
1      2      8      5             8
2      3      2      0             8
3      4      5      5             5
4      5      2      5             5
5      6      0      2             5

相关问题 更多 >