繁体   English   中英

如果列表中有多个元素不为零,则计算列表元素的差异

[英]Calculate the difference of list elements if more than one element in the list is not zero

有一个如下所示的数据集:

Date       Item        A.unit       B.Unit    C.Unit      D.Unit   
10/11       A,D          5            0         0          12
11/11       A,B,C       10            10        5          0
12/11       A           20             0        0           0  

我想要 output 列,这样每当列表中有多个元素时,它将计算单位的差异,当存在单个元素时,它将显示零。 所以 output 将是:

Date       Item        A.unit       B.Unit    C.Unit      D.Unit          output
    10/11       A,D          5            0         0          12           5-12=-7 
    11/11       A,B,C       10            10        5          0            10-10-5=-5
    12/11       A           20             0        0           0            0--since only one element is there

谁能告诉我如何获得 output 列。

没有检查Item列的解决方案 - 它使用每个Unit列的第一个非 0 值并减去值的总和,如果只有 1 个值设置0

#all columns without first and second
df1 = df.iloc[:, 2:].mask(lambda x: x==0)
#alternative
#all columns with Unit in column names
#df1 = df.filter(like='Unit').mask(lambda x: x==0)
first = df1.bfill(axis=1).iloc[:, 0]
df['output'] = np.where(df1.count(axis=1) == 1, 0, first - df1.sum(axis=1) + first)
print (df)
    Date   Item  A.Unit  B.Unit  C.Unit  D.Unit  output
0  10/11    A,D       5       0       0      12    -7.0
1  11/11  A,B,C      10      10       5       0    -5.0
2  12/11      A      20       0       0       0     0.0

Item列匹配的解决方案 - 如果只有一个值和最后一个聚合sum ,则将Item分解为行,乘以-10firstjoin

df = df.assign(Item = df['Item'].str.split(',')).explode('Item').reset_index(drop=True)
df['new'] = df.lookup(df.index, df['Item'] + '.Unit')

df.loc[df.duplicated(subset=['Date']), 'new'] *=  -1
df.loc[~df.duplicated(subset=['Date'], keep=False), 'new'] =  0


d1 = dict.fromkeys(df.columns.difference(['Date','Item','new']), 'first')
fin = {**{'Item':','.join}, **d1, **{'new':'sum'}}
df = df.groupby('Date', as_index=False).agg(fin)

print (df)
    Date   Item  A.Unit  B.Unit  C.Unit  D.Unit  new
0  10/11    A,D       5       0       0      12   -7
1  11/11  A,B,C      10      10       5       0   -5
2  12/11      A      20       0       0       0    0

这是一种解决方案。 第一步是创建一个 function ,它在一个特定的行上完全符合您的要求:

from functool import reduce
def sum_function(x):
  if len(x[x != 0]) == 1:
    return 0
  else:
    return reduce(lambda a,b: a-b, x)

如果该行中只有一个元素不为 0,则返回 0。如果有更多元素,则将它们全部减去。 以下是如何将 function 应用于每一行:

columns = ['A.unit', 'B.unit', 'C.unit', 'D.unit']
df.apply(lambda x: sum_function(x[columns]), axis=1)

结果是:

0   -7
1   -5
2    0

您可以将其添加为新列:

df['output'] = df.apply(lambda x: sum_function(x[columns]), axis=1)

尝试:

def calc(row):
    out = row[np.argmax(np.array(row.tolist()) > 0)]
    for c in row.values[np.argmax(np.array(row.tolist()) > 0)+1:]:
        out -= c
    if out == row.sum():
        return 0
    else:
        return out

df['output'] = df.drop(['Date','Item'], axis=1).apply(calc, axis=1)

Output:

    Date   Item  A.unit  B.Unit  C.Unit  D.Unit  output
0  10/11    A,D       5       0       0      12      -7
1  11/11  A,B,C      10      10       5       0      -5
2  12/11      A      20       0       0       0       0

使用lambda, regex

unit_columns = list(df.columns[2:])
regex = re.compile(re.escape('.Unit'), re.IGNORECASE)
unit_columns_replaced = [regex.sub('', a) for a in unit_columns]

def output(row):
    ItemN = row['Item'].split(",")
    if len(ItemN) < 2:
        return 0
    idxs = np.where(np.in1d(unit_columns_replaced, ItemN))[0]
    c_names = [unit_columns[idx] for idx in idxs]
    f_columns = row.filter(items=c_names)
    return 2 * f_columns[0] - f_columns.sum()


df['output'] = df.apply(lambda row: output(row), axis=1)
df

给出 output 为

    Date    Item    A.unit  B.Unit  C.Unit  D.Unit  output
0   10/11   A,D     5   0   0   12  -7
1   11/11   A,B,C   10  10  5   0   -5
2   12/11   A   20  0   0   0   0

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM