[英]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
分解为行,乘以-1
和0
, first
是join
:
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.