Python在附加到空数组时更改数据
在工作中,我遇到了一些关于熊猫DF和append的奇怪行为 目标是使用Python在附加到空数组时更改数据,python,arrays,pandas,Python,Arrays,Pandas,在工作中,我遇到了一些关于熊猫DF和append的奇怪行为 目标是使用RowNum行数生成DF,重复UniqueInt值,并从UniqueInt+1开始直到RowNum生成一列新的连续数字。这是一种用相同的先前数据填充中间的空数据的方法 我主要关心的不是如何实现这一点,而是为什么在将结果追加到空数据帧时,结果数据与代码的输出不一致(即:追加会更改所追加数据的值) 这是在Python3.7.4上实现的 我创建了一个非常小的可复制示例: import pandas as pd import nump
RowNum
行数生成DF,重复UniqueInt
值,并从UniqueInt
+1开始直到RowNum
生成一列新的连续数字。这是一种用相同的先前数据填充中间的空数据的方法
我主要关心的不是如何实现这一点,而是为什么在将结果追加到空数据帧时,结果数据与代码的输出不一致(即:追加会更改所追加数据的值)
这是在Python3.7.4上实现的
我创建了一个非常小的可复制示例:
import pandas as pd
import numpy as np
#Create a DF
TemporalDF=pd.DataFrame([2,2,3,3,3,7,7,7,8,8,8,9,9,10,10,10])
TemporalDF.columns=['Int']
#Create recipients for data
BuggedResult=[]
CorrectResult=pd.DataFrame()
# For loop
for UniqueInt in range(TemporalDF['Int'].unique()[0],10):
# Specify desired number of rows
RowNum=(10-UniqueInt)
# Subset original data
Temp=TemporalDF[TemporalDF['Int']==UniqueInt]
# Fill gaps of data based on last correctly recorded data
if(Temp.shape[0]==0):
# Take last recorded value
DummyDF=DummyDF.iloc[1:DummyDF.shape[0]+1,:]
DummyDF['FillIntStart']=np.repeat(a=UniqueInt, repeats=RowNum)
else:
# Create empty data frame
DummyDF=pd.DataFrame()
# Populate
DummyDF['FillIntStart']=np.repeat(a=UniqueInt, repeats=RowNum)
DummyDF['FillIntEnd']=[UniqueInt+i for i in range(1,RowNum+1)]
# Save results
BuggedResult.append(DummyDF)
CorrectResult=CorrectResult.append(other=DummyDF, ignore_index=True)
pass
使用此代码,您可以看到有两种存储数据的方法:
BuggedResult.append()
pd.append()
方法BuggedResult
(BuggedResult[0]
)数组的第一个元素正常,如下所示:
┌──────────────┬────────────┐
│ FillIntStart │ FillIntEnd │
├──────────────┼────────────┤
│ 2 │ 3 │
│ 2 │ 4 │
│ 2 │ 5 │
│ 2 │ 6 │
│ 2 │ 7 │
│ 2 │ 8 │
│ 2 │ 9 │
│ 2 │ 10 │
└──────────────┴────────────┘
┌──────────────┬────────────┐
│ FillIntStart │ FillIntEnd │
├──────────────┼────────────┤
│ 3 │ 4 │
│ 4 │ 5 │
│ 5 │ 6 │
│ 6 │ 7 │
│ 6 │ 8 │
│ 6 │ 9 │
│ 6 │ 10 │
└──────────────┴────────────┘
但是第二个元素(BuggedResult[1]
)如下所示:
┌──────────────┬────────────┐
│ FillIntStart │ FillIntEnd │
├──────────────┼────────────┤
│ 2 │ 3 │
│ 2 │ 4 │
│ 2 │ 5 │
│ 2 │ 6 │
│ 2 │ 7 │
│ 2 │ 8 │
│ 2 │ 9 │
│ 2 │ 10 │
└──────────────┴────────────┘
┌──────────────┬────────────┐
│ FillIntStart │ FillIntEnd │
├──────────────┼────────────┤
│ 3 │ 4 │
│ 4 │ 5 │
│ 5 │ 6 │
│ 6 │ 7 │
│ 6 │ 8 │
│ 6 │ 9 │
│ 6 │ 10 │
└──────────────┴────────────┘
当它看起来像这样时(取自CorrecResult表,使用pd.append()
):
换句话说,append方法是在我追加数据后更改我的数据。如果您检查代码,还可以尝试我已经尝试过的几种方法,比如手动跟踪循环,添加DummyDF.to_txt()
方法来读取单独文件中的数据,等等。逻辑似乎还可以,但当我将其附加到空数组时,结果会发生变化
这是Python3.7.4所期望的奇怪行为吗?不建议在空数组中添加DF,因为pandas已经有了解决方案,但我认为更改数据太多了
我真诚地希望这个问题是我的,因为我不是Python专家。。。那么,有什么想法吗
谢谢 我是这样做的:
>>> temporal = np.array([2,2,3,3,3,7,7,7,8,8,8,9,9,10,10,10])
>>> max_temporal = np.max(temporal)
>>> result = []
>>> columns = ['FillIntStart', 'FillIntEnd']
>>> for x in np.unique(temporal):
... start = np.repeat(x, max_temporal - x)
... end = np.arange(x + 1, max_temporal + 1)
... result.append(pd.DataFrame({columns[0]: start, columns[1]: end}, columns=columns))
...
>>> result = pd.concat(result)
>>> print(result.to_string(index=False))
FillIntStart FillIntEnd
2 3
2 4
2 5
2 6
2 7
2 8
2 9
2 10
3 4
3 5
3 6
3 7
3 8
3 9
3 10
7 8
7 9
7 10
8 9
8 10
9 10
如果我理解的话,这就是你想要达到的结果
我必须仔细查看您的代码,以了解它的错误。特别是,我不太明白这部分到底在做什么:
# Fill gaps of data based on last correctly recorded data
if(Temp.shape[0]==0):
# Take last recorded value
DummyDF=DummyDF.iloc[1:DummyDF.shape[0]+1,:]
DummyDF['FillIntStart']=np.repeat(a=UniqueInt, repeats=RowNum)
此代码一开始就有问题,因为运行时可能尚未定义DummyDF
(仅当else:
块在上一个循环中运行时)。我不太清楚在这种情况下你想做什么,因为它似乎在处理[2,10]范围内的缺失值,而这些值不在你原来的TemporalDF
中,我认为你没有解释在这种情况下你想做什么。您正在重用前面循环中的DummyDF
这一事实是导致您的bug的原因。当我逐步了解您的代码时(这是一项值得学习的调试您自己的代码的技能),我发现这里发生了什么:因为您正在修改一个DataFrame
,您随后的循环最终修改了BuggedResult
列表中已经存在的同一个DataFrame
实例。使用DataFrame.append
不会出现此问题,因为它会将数据复制到CorrectResult
,并在此过程中调整其数据缓冲区的大小
如果可能的话,我会尽量避免使用DataFrame.append
——这里使用一个pd.concat
,就像我的示例中那样,效率更高,因为它可以为所有输出构建一个大小正确的DataFrame
,然后复制一次。也许有更好的解决办法,但目前还没有想到
(顺便说一句,Python有一个关于如何格式化代码的样式指南,建议变量名使用小写,而CamelCase通常用于类名。当然,不要求您使用小写,一致性是最重要的。但大多数Python社区都试图坚持这些约定,因此有点不一致ng以读取不需要的代码。感谢您的回答。是的,代码正在尝试处理中间缺少的值,用来自上一个DummyDF的相同数据填充它们。因为我使用的数据的性质是不可能的,因为在计算Temp.shape[0]==0时,第一个循环返回True,所以这永远不会是一个问题(当然,在我的特定场景中)。我知道还有其他方法可以解决这个问题,但我关心的不是如何解决,而是为什么将数据添加到空数组会更改数据。另外,非常感谢样式指南!我刚刚更新了我的答案,试图解释这个错误。我不太清楚您想要如何处理这个错误“缺少”值:如果您的数据范围从[2,10]开始,为什么还要费心调用
.unique()
呢?因为我使用的数据的性质是不可能的,因为在计算Temp.shape[0]==0时,第一个循环返回True“在这种特殊情况下可能是这样,但正如您自己所指出的,它不是非常健壮,而且会使代码更加混乱和难以理解。我将避免将此作为一般原则。append
返回一个新的数据帧,并且不会修改原始数据帧。