Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/359.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 从数据帧中删除取消行_Python_Pandas_Dataframe - Fatal编程技术网

Python 从数据帧中删除取消行

Python 从数据帧中删除取消行,python,pandas,dataframe,Python,Pandas,Dataframe,我有一份寄给客户的发票清单。但是,有时会发送坏发票,随后会取消。我的Pandas数据框看起来像这样,只是大得多(约300万行) 现在,我想删除所有行,其中客户、发票编号和日期相同,但金额的值相反。 发票的更正总是在发票编号相同的同一天进行。发票编号唯一地绑定到客户,并且始终对应于一个交易(可以由多个组件组成,例如,customer=2,invoice\u nr=4)。发票更正只能在更改已收费的金额或将金额拆分为较小的部分时进行。因此,取消的值不会在同一张发票上重复 如果您能提供任何有关如何编程的

我有一份寄给客户的发票清单。但是,有时会发送坏发票,随后会取消。我的Pandas数据框看起来像这样,只是大得多(约300万行)

现在,我想删除所有行,其中
客户
发票编号
日期
相同,但
金额
的值相反。
发票的更正总是在发票编号相同的同一天进行。发票编号唯一地绑定到客户,并且始终对应于一个交易(可以由多个组件组成,例如,
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项。但这对我来说似乎是一个完美的解决方案!这会删除绝对值相同的行,因此之前会相互取消。如果你在一个单独的回复中发布这个,我会把它标记为已接受的答案。或者我遗漏了什么?嗯,我认为这只是测试的解决方案,因为如果你有两次以上的重复,你就会丢失你的好数据-见sample
df=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'}})
和value
10
。那么这种情况在真实数据中是可能的?
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