Python 从数据帧中删除取消行
我有一份寄给客户的发票清单。但是,有时会发送坏发票,随后会取消。我的Pandas数据框看起来像这样,只是大得多(约300万行) 现在,我想删除所有行,其中Python 从数据帧中删除取消行,python,pandas,dataframe,Python,Pandas,Dataframe,我有一份寄给客户的发票清单。但是,有时会发送坏发票,随后会取消。我的Pandas数据框看起来像这样,只是大得多(约300万行) 现在,我想删除所有行,其中客户、发票编号和日期相同,但金额的值相反。 发票的更正总是在发票编号相同的同一天进行。发票编号唯一地绑定到客户,并且始终对应于一个交易(可以由多个组件组成,例如,customer=2,invoice\u nr=4)。发票更正只能在更改已收费的金额或将金额拆分为较小的部分时进行。因此,取消的值不会在同一张发票上重复 如果您能提供任何有关如何编程的
客户
、发票编号
和日期
相同,但金额
的值相反。发票的更正总是在发票编号相同的同一天进行。发票编号唯一地绑定到客户,并且始终对应于一个交易(可以由多个组件组成,例如,
customer=2
,invoice\u nr=4
)。发票更正只能在更改已收费的金额
或将金额
拆分为较小的部分时进行。因此,取消的值不会在同一张发票上重复
如果您能提供任何有关如何编程的帮助,我们将不胜感激。如果您只需对所有3个字段执行groupby操作,会怎么样?由此产生的金额将扣除任何已取消的发票:
df2 = df.groupby(['customer','invoice_nr','date']).sum()
导致
customer invoice_nr date
1 1 2016/01/01 11
2 2016/02/01 10
2 3 2016/01/01 7
def删除\u取消的\u事务(df):
trans_neg=df.金额<0
返回df.loc[~(trans_neg | trans_neg.shift(-1))]
组=[df.customer,df.invoice\u nr,df.date,df.amount.abs()]
groupby(组,如索引=False,组关键字=False)\
.应用(删除\取消\交易)
您可以使用所有值,其中每个组的值的和为0
,模为2
为0
:
print (df.groupby([df.customer, df.invoice_nr, df.date, df.amount.abs()])
.filter(lambda x: (len(x.amount.abs()) % 2 == 0 ) and (x.amount.sum() == 0)))
customer invoice_nr amount date
index
0 1 1 10 01-01-2016
1 1 1 -10 01-01-2016
5 2 4 12 02-01-2016
6 2 4 -12 02-01-2016
idx = df.groupby([df.customer, df.invoice_nr, df.date, df.amount.abs()])
.filter(lambda x: (len(x.amount.abs()) % 2 == 0 ) and (x.amount.sum() == 0)).index
print (idx)
Int64Index([0, 1, 5, 6], dtype='int64', name='index')
print (df.drop(idx))
customer invoice_nr amount date
index
2 1 1 11 01-01-2016
3 1 2 10 02-01-2016
4 2 3 7 01-01-2016
7 2 4 8 02-01-2016
8 2 4 4 02-01-2016
按注释编辑:
如果一张发票、一个客户和一个日期的实际数据不重复,则可以使用以下方法:
print (df)
index customer invoice_nr amount date
0 0 1 1 10 01-01-2016
1 1 1 1 -10 01-01-2016
2 2 1 1 11 01-01-2016
3 3 1 2 10 02-01-2016
4 4 2 3 7 01-01-2016
5 5 2 4 12 02-01-2016
6 6 2 4 -12 02-01-2016
7 7 2 4 8 02-01-2016
8 8 2 4 4 02-01-2016
df['amount_abs'] = df.amount.abs()
df.drop_duplicates(['customer','invoice_nr', 'date', 'amount_abs'], keep=False, inplace=True)
df.drop('amount_abs', axis=1, inplace=True)
print (df)
index customer invoice_nr amount date
2 2 1 1 11 01-01-2016
3 3 1 2 10 02-01-2016
4 4 2 3 7 01-01-2016
7 7 2 4 8 02-01-2016
8 8 2 4 4 02-01-2016
尝试读取dict
中的行,其中invoice\u nr
和date
由任何分隔符分隔,例如
。现在如果你有多余的钥匙,就把它删除。@KrishnachandraSharma我不太确定我是否明白你的意思。我是否应该将发票编号
和日期
作为dict
键读取?然后我将如何处理具有相同<代码>发票编号
和<代码>日期的多行?由于您希望删除具有相同<代码>发票编号和<代码>日期的所有行,因此将键字符串准备为<代码>发票编号#日期将帮助您确定要删除的重复行。感谢您的快速回复。但是,我不想删除所有具有相同发票编号
和日期
的行,而只删除那些具有相反金额
值的行。例如,我不想从数据帧中删除第3行。在列amount
中的index=3
行中是否可能是值10
在实际数据中?嗯,我认为这更复杂,因为需要删除金额的相反值。这很难…谢谢。嗯,我认为你的解决方案更好,因为更一般。我的解决方案更快,但无法找到某些值。Thx@jezrael。这是一个有趣的问题。我还在考虑。谢谢@piRSquared!我很高兴你喜欢这个问题。你的解决方案非常棒。不幸的是,groupby
在我的300万行上花费了很长时间。这当然适用于较小的数据集,而且正是我所需要的!谢谢,这是一个很好的解决方案。但是,我现在看到,我的示例数据不够完整,因为我的发票偶尔会以较小的数量分开,我想分开考虑。我相应地更新了我原来的问题。非常感谢你的帮助,@jezrael!与@piRSquared的解决方案类似,您的解决方案对于小数据集非常有效。不幸的是,对于我的300万行数据帧,操作需要相当长的时间。是的,您的任务非常复杂。因此,如果你需要更快的速度,这是有问题的。但有一个问题-300万行中取消发票的频率(估计)?您可以获得所有副本的df1
:df['amount\u abs']=df.amount.abs()
df1=df[df.duplicated(['customer','invoice\u\n nr','amount\u abs'],keep=False)]
打印(df1)df1的大小是多少len(df1)
len(df1)
短约30000项。但这对我来说似乎是一个完美的解决方案!这会删除绝对值相同的行,因此之前会相互取消。如果你在一个单独的回复中发布这个,我会把它标记为已接受的答案。或者我遗漏了什么?嗯,我认为这只是测试的解决方案,因为如果你有两次以上的重复,你就会丢失你的好数据-见sampledf=pd.DataFrame({'index':{0:0,1:1,2:2,3:3,4:4},'invoice_nr':{0:1,1:1,2:1,3:2},'customer':{0:1,1,3:1,4:2},'amount{0:10,1:-10,2:10,3:11,4:7},'日期:{0:01-2016',1:01-2016',2:01-2016',3:02-01-2016',4:01-01-2016'}})
和value10
。那么这种情况在真实数据中是可能的?
print (df.groupby([df.customer, df.invoice_nr, df.date, df.amount.abs()])
.filter(lambda x: (len(x.amount.abs()) % 2 == 0 ) and (x.amount.sum() == 0)))
customer invoice_nr amount date
index
0 1 1 10 01-01-2016
1 1 1 -10 01-01-2016
5 2 4 12 02-01-2016
6 2 4 -12 02-01-2016
idx = df.groupby([df.customer, df.invoice_nr, df.date, df.amount.abs()])
.filter(lambda x: (len(x.amount.abs()) % 2 == 0 ) and (x.amount.sum() == 0)).index
print (idx)
Int64Index([0, 1, 5, 6], dtype='int64', name='index')
print (df.drop(idx))
customer invoice_nr amount date
index
2 1 1 11 01-01-2016
3 1 2 10 02-01-2016
4 2 3 7 01-01-2016
7 2 4 8 02-01-2016
8 2 4 4 02-01-2016
print (df)
index customer invoice_nr amount date
0 0 1 1 10 01-01-2016
1 1 1 1 -10 01-01-2016
2 2 1 1 11 01-01-2016
3 3 1 2 10 02-01-2016
4 4 2 3 7 01-01-2016
5 5 2 4 12 02-01-2016
6 6 2 4 -12 02-01-2016
7 7 2 4 8 02-01-2016
8 8 2 4 4 02-01-2016
df['amount_abs'] = df.amount.abs()
df.drop_duplicates(['customer','invoice_nr', 'date', 'amount_abs'], keep=False, inplace=True)
df.drop('amount_abs', axis=1, inplace=True)
print (df)
index customer invoice_nr amount date
2 2 1 1 11 01-01-2016
3 3 1 2 10 02-01-2016
4 4 2 3 7 01-01-2016
7 7 2 4 8 02-01-2016
8 8 2 4 4 02-01-2016