更改单行值时保持和约束行的比例性

2024-05-16 10:28:10 发布

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

我有一个由成分数据组成的数据集。 每一列代表一种成分在整个混合物中的百分比(十进制值)。 每行相加为1。你知道吗

如果混合物中的一个组分发生变化,其余组分必须相应地变化,以满足总和约束。你知道吗

我正在用这些数据进行多元线性回归,它需要一些转换,以便回归系数是有意义的和可解释的。数据集包含零值,对于我尝试实现的特定类型的转换来说,这是一个问题。你知道吗

在执行此转换之前,建议的操作是用一个小数字替换所有零值,并调整其余组件的值,以便仍然满足求和约束。你知道吗

您可以在下面的虚拟df中看到一行中有超过1个零值的情况。你知道吗

data = {'X1': [0.21, 0.08, 0.57, 0.03],
        'X2': [0.27, 0.56, 0.0, 0.02],
        'X3': [0.0, 0.14, 0.0, 0.45],
        'X4': [0.13, 0.02, 0.26, 0.37],
        'X5': [0.39, 0.2, 0.17, 0.13]}

df = pd.DataFrame(data)

print(df)

我们只考虑一行,因此计算公式如下:

让原始值为r_i。对于delta_ir_i分量的变化,我们得到新的值x_i。你知道吗

所以,x_i = r_i + delta_i

为了保持剩余成分之间的相对比例

r_j是剩余组件的原始值

第j个分量x_j的新值是

x_j = r_j - ((r_j / (1 - r_i) * delta_i) and i != j

我正在努力为这个问题编写一个合适的循环,它将在数据集中搜索零值,然后在索引和列中添加一个小数字 包含零值,然后用上面描述的公式调整整行。你知道吗

编辑:

很抱歉数学公式的表述不好。你知道吗

对于虚拟数据框中的第一行,公式的应用是直接的,因为该行中只有一个零:

Table showing updated values of X1, X2, X4 and X5 when a small value is added to X3

重要的是,其余组件之间的相对比例保持不变,您可以在这里看到,当我将零值更新为一个小数字时。你知道吗

Relative proportions from the first row of the dummy df

对于虚拟数据框的第三行,事情变得有点复杂。我通过添加一个小数字来更新第一个(X2)零值。第二个(X3)零值保持为零,因为公式是乘零和除零。 所以我做了第二次更新,使得X2和X3现在是很小的非零值,这显示在下表的第三行。你知道吗

Table showing updated values of X1, X4 and X5 when a small value is added to X2 and X3

对于行中存在多个0的情况,保持其余组件之间的相对比例也是同样的情况。你知道吗

Relative proportions from the third row of the dummy df

我想不出第一个问题的循环,更别说第二个了! 另外,不要担心用相对比例表中的一个小数字除以所产生的大数字,我稍后会处理这个问题。你知道吗


Tags: 数据dfdata情况组件数字比例公式
2条回答

以下是答案:

import pandas as pd
# To show 10 decimal points.
pd.options.display.float_format = '{:.10f}'.format

data = {'X1': [0.21, 0.08, 0.57, 0.03],
        'X2': [0.27, 0.56, 0.0, 0.02],
        'X3': [0.0, 0.14, 0.0, 0.45],
        'X4': [0.13, 0.02, 0.26, 0.37],
        'X5': [0.39, 0.2, 0.17, 0.13]}

df = pd.DataFrame(data)

delta_i = 0.000001
r_i = 0.0

# Provided formula.
def adjust_proportion(r_j, r_i, delta_i):
    return r_j - ((r_j / (1 - r_i)) * delta_i)

# For row-wise application.
def adjust_row(row, r_i, delta_i):

    # Get all zeros and their count in the row.
    zero_mask = (row == 0)
    zero_count = row[zero_mask].shape[0] # Get only x.

    # For every zero, adjust proportions for "cells" not in mask.
    for i in range(zero_count):
        row[~zero_mask] = row[~zero_mask].apply(lambda x: adjust_proportion(x, r_i, delta_i))

    # Increase the mask by delta_i across the board.
    row[zero_mask] += delta_i

    return row

# Apply ROW-WISE using axis=1.
df.apply(lambda x: adjust_row(x, r_i, delta_i), axis=1)
print(df)

# Check sums.
print(df.apply(lambda x: x.sum(), axis=1))

结果如下:

enter image description here

有更多的最佳方法,但这应该照顾到一般的逻辑。你知道吗

您可以使用:

def exclude_zero(e, delta_i):
    """Replace zeros with a delta_i value by keeping the other non zeros value in the same distribution and total sum to 1"""

    zero_count = e.count(0)
    extra_amount = zero_count * delta_i

    for index, value in enumerate(e):
        if value == 0 :
            e[index] = delta_i
        else:
            e[index] = value * (1 - extra_amount)

    return e

data = {'X1': [0.21, 0.08, 0.57, 0.03],
        'X2': [0.27, 0.56, 0.0, 0.02],
        'X3': [0.0, 0.14, 0.0, 0.45],
        'X4': [0.13, 0.02, 0.26, 0.37],
        'X5': [0.39, 0.2, 0.17, 0.13]}

df = pd.DataFrame(data)

for index in range(len(df)):
    df.iloc[index] = exclude_zero(df.iloc[index].values.tolist(), 0.000001)

pd.options.display.precision = 8

df

enter image description here

相关问题 更多 >