Python在附加到空数组时更改数据

2024-05-14 03:28:41 发布

您现在位置:Python中文网/ 问答频道 /正文

在工作中,我遇到了一些关于熊猫DF和append的奇怪行为

目标是生成一个行数为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

使用此代码,您可以看到有两种存储数据的方法:

  1. 使用BuggedResult.append()
  2. 使用熊猫的pd.append()方法

BuggedResultBuggedResult[0])数组的第一个元素正常,如下所示:

┌──────────────┬────────────┐
│ FillIntStart │ FillIntEnd │
├──────────────┼────────────┤
│            2 │          3 │
│            2 │          4 │
│            2 │          5 │
│            2 │          6 │
│            2 │          7 │
│            2 │          8 │
│            2 │          9 │
│            2 │         10 │
└──────────────┴────────────┘

但是第二个元素(BuggedResult[1])如下所示:

┌──────────────┬────────────┐
│ FillIntStart │ FillIntEnd │
├──────────────┼────────────┤
│            3 │          4 │
│            4 │          5 │
│            5 │          6 │
│            6 │          7 │
│            6 │          8 │
│            6 │          9 │
│            6 │         10 │
└──────────────┴────────────┘

当它看起来像这样时(从CorrecResult表中,使用pd.append()):

┌──────────────┬────────────┐
│ FillIntStart │ FillIntEnd │
├──────────────┼────────────┤
│            3 │          4 │
│            3 │          5 │
│            3 │          6 │
│            3 │          7 │
│            3 │          8 │
│            3 │          9 │
│            3 │         10 │
└──────────────┴────────────┘

换句话说,append方法是在我追加数据后更改我的数据。如果您检查代码,您还可以尝试我已经尝试过的几种方法,比如手动跟随循环,添加DummyDF.to_txt()方法来读取单独文件中的数据,等等。逻辑似乎还可以,但当我将其附加到空数组时,结果会发生变化

这是Python3.7.4所期望的奇怪行为吗?不建议在空数组中添加DF,因为pandas已经有了解决方案,但我认为更改数据太多了

我真诚地希望这个问题是我的,因为我不是Python专家。。。那么,有什么想法吗

谢谢


Tags: 数据方法代码dfdatanppdappend
1条回答
网友
1楼 · 发布于 2024-05-14 03:28:41

我是这样做的:

>>> 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这一事实是导致错误的原因。当我在pdb(一种值得学习调试自己代码的技能)中逐步查看您的代码时,我发现这里发生了什么:因为您正在修改一个DataFrame实例,您随后的循环最终修改了BuggedResult列表中已经存在的同一个DataFrame实例。DataFrame.append不会出现这个问题,因为它会将数据复制到CorrectResult,并在过程中调整其数据缓冲区的大小

如果可能的话,我会尽量避免使用DataFrame.append,在我的示例中使用单个pd.concat更有效,因为它可以为所有输出构造一个大小正确的DataFrame,然后复制到其中一次,而不是调整每个循环上的数据大小。也许有更好的解决办法,但目前还没有想到

(顺便说一句,Python有一个样式指南PEP 8关于如何格式化您的代码,这建议变量名使用小写,而CamelCase通常保留为类名。当然,不要求您使用小写,一致性最为重要。但大多数Python社区都试图遵守这些约定,因此阅读不使用小写的代码有点刺耳)

相关问题 更多 >