python - 如何匹配数据框中的相反值?
问题描述
我基本上想从导入的数据框中消除相反的数量。
我的解决方案是构建一个新的数据框,忽略成对组合的总和为零的行。
考虑以下数据框:
df = pd.DataFrame([
['31/07/17', 43020500, 13552.65],
['31/07/17', 43020500, 13552.65],
['31/07/17', 43020500, 13552.65],
['31/07/17', 43020500, 13552.65],
['31/08/17', 43020500, 241024.48],
['31/08/17', 43020500, 241024.48],
['31/08/17', 43020500, 241024.48],
['31/08/17', 43020500, 241024.48],
['31/08/17', 43020500, 241024.48],
['31/08/17', 43020500, -13552.65],
['31/08/17', 43020500, -13552.65],
['31/08/17', 43020500, -13552.65],
['31/08/17', 43020500, -13552.65],
['31/08/17', 43020500, -13552.65],
['30/06/17', 43020500, 133540.13],
], columns = ['Data', 'Account','Amount']
)
df
Out[34]:
Data Account Amount
0 31/07/17 43020500 13552.65
1 31/07/17 43020500 13552.65
2 31/07/17 43020500 13552.65
3 31/07/17 43020500 13552.65
4 31/08/17 43020500 241024.48
5 31/08/17 43020500 241024.48
6 31/08/17 43020500 241024.48
7 31/08/17 43020500 241024.48
8 31/08/17 43020500 241024.48
9 31/08/17 43020500 -13552.65
10 31/08/17 43020500 -13552.65
11 31/08/17 43020500 -13552.65
12 31/08/17 43020500 -13552.65
13 31/08/17 43020500 -13552.65
14 30/06/17 43020500 133540.13
预期结果是由索引 4 到 8、13 和 14 组成的新数据框,但我的代码无法正常工作......
import numpy as np
import pandas as pd
pd.options.display.float_format = '{:,.2f}'.format
df = pd.read_excel('ContractAssets_copy.XLSX')
df.sort_values('Date')
dfToList = df['Amount'].tolist()
newdf = []
def index(a_list, value):
try:
return a_list.index(value)
except ValueError:
return None
for number in dfToList:
key = index(dfToList, dfToList[number] * -1)
if key == None:
newdf.append(df[number])
newdf
我该如何解决这个问题?
解决方案
请注意,例如,您有4个13552.65值,但相反值 ( -13552.65 ) 的数量是5。
因此,如果每个值只消除一个相反的值,那么在这种情况下,应该留下一个负值(另一种解决方案不遵守这一原则)。
从定义一个函数开始,以消除“不需要的”行(从当前行组中):
def eliminate(grp):
grpSorted = grp.sort_values('Amount')
amt = grpSorted.Amount
nNeg = np.count_nonzero(amt.lt(0))
nPos = amt.size - nNeg
if nNeg == 0 or nPos == 0: # No opposite values
return grp
vDiff = nNeg - nPos
return grpSorted.head(vDiff) if vDiff > 0 else grpSorted.tail(-vDiff)
然后添加AmountAbs列:
df['AmountAbs'] = df.Amount.abs()
因为我们应该只根据Amount的绝对值对行进行分组。
最后,您可以进行所需的分组并将上述功能应用于每个组:
df.groupby('AmountAbs').apply(eliminate)\
.reset_index(level=0, drop=True)\
.drop(columns=['AmountAbs'])
上述说明中的“收尾行动”包括:
- 从索引中删除AmountAbs(仅保留原始索引),
- 删除AmountAbs列。
如果您愿意,可以添加.sort_index()
到上述指令,以恢复原始行顺序。
编辑
还有更短的解决方案,无需创建任何辅助列(并在最后删除它)。
消除函数略有不同:
def elim(grp):
grpSorted = grp.sort_values('Amount')
amt = grpSorted.Amount
nNeg = np.count_nonzero(amt.lt(0)) # No of negative values
nPos = amt.size - nNeg # No of positive values
vDiff = nNeg - nPos
return grpSorted.head(vDiff) if vDiff > 0 else grpSorted.tail(-vDiff)
并应用它,运行:
df.groupby(lambda x: abs(df.loc[x, 'Amount']))\
.apply(elim).reset_index(level=0, drop=True)
推荐阅读
- azure-app-configuration - 从 Azure 应用配置中选择标记值和未标记值
- python - 在 python 中,如何修复列表索引超出范围的问题?
- google-cloud-platform - GCE:'未能注册层'
- regex - Google Apps 脚本中用于替换 Rs 的正则表达式
- django - 如何扩展 Django Queryset 的 select_related 函数的范围,使其包含与原始表相关的表相关的表
- doctrine - 语法错误 line 0, col 84: Error: Expected end of string, got 'f9f03b9a61c46db91ed492c862a3083'
- php - PHP Postgres Driver 9.2.18 的简单选择问题
- recursion - 查找二叉搜索树从根到特定键的距离
- java - 如何使用接口方法?
- java - 使用时间格式化日期,仅当日期有时间时