【问题标题】:How to create/populate missing rows in a DataFrame?如何在 DataFrame 中创建/填充缺失的行?
【发布时间】:2020-12-10 01:56:30
【问题描述】:

我有一个数据文件,其中包含每列火车每秒的能源使用情况,但生成数据文件的应用程序消除了所有能源使用为 0 的行,我需要重新创建这些行。

具体需求是:对于每个车次,确保每秒至少有一条记录,如果需要添加记录,则使用0表示能量。

我的初始 DataFrame 如下所示(秒是自午夜以来的时间戳):

           train  seconds    energy   
0           1024    13980  105.0000   
1           1024    14745  114.0000   
2           1024    14746  127.0100 
3           1024    14747  137.5667 
...          ...      ...       ...      
4284449     7564    95495 -301.6824   
4284450     7564    95496 -181.0630   
4284451     7564    95497  -60.3713  

请注意,第 0 行和第 1 行之间的时间间隔为 14745-13980 = 765 秒。据我们所知,每辆火车的每秒记录中唯一的差距是在第一条记录和第二条记录之间,您可以从秒值的差异中看出有多少缺失。但是由于我需要为每列火车的每一秒丢失一行,因此最好不要假设唯一的缺失值在第一条记录和第二条记录之间。

我的计划是:

  1. 按火车分组以获得每列火车的最短和最长秒数
  2. 从火车的乘积和范围(最小,最大)中为每列火车生成一个新的数据帧。这将为我提供每列火车和每列火车每一秒的 DataFrame,并且没有能量列。
  3. 对原始数据框执行新的 DataFrome 左合并,这将为之前不存在的任何行的能量 NA 值
  4. 将所有 NA 能量值替换为 0,就完成了。

第 1 步:

# Get the minimum and maximum seconds value per train   
df = df_datafile.groupby(['train'])['seconds'].agg(['min', 'max']).rename(
                         columns={'min': 'minsec', 'max': 'maxsec'})

导致:

              minsec  maxsec
    train                
    1001       21923   25302
    1003       22825   26197
    1005       23736   27207
    1007       24620   28009
    1011       25548   28889
    ...          ...     ...
    VIAE858    52785   53380
    VIAE87     53442   54262
    VIAE88     83204   85785
    VIAE97     21942   27054
    VIAE98     71123   73186

第 2 步:

# Create one (train, second) record for every second of every train 
df = DataFrame([product(*[[train], arange(minsec, maxsec)])
               for train, minsec, maxsec in list(zip(df.index, df.minsec, df.maxsec))])

导致:

                 0                 1                 2      ... 35403 35404 35405
0        (1001, 21923)     (1001, 21924)     (1001, 21925)  ...  None  None  None
1        (1003, 22825)     (1003, 22826)     (1003, 22827)  ...  None  None  None
2        (1005, 23736)     (1005, 23737)     (1005, 23738)  ...  None  None  None
3        (1007, 24620)     (1007, 24621)     (1007, 24622)  ...  None  None  None
4        (1011, 25548)     (1011, 25549)     (1011, 25550)  ...  None  None  None
...                ...               ...               ...  ...   ...   ...   ...
2561  (VIAE858, 52785)  (VIAE858, 52786)  (VIAE858, 52787)  ...  None  None  None
2562   (VIAE87, 53442)   (VIAE87, 53443)   (VIAE87, 53444)  ...  None  None  None
2563   (VIAE88, 83204)   (VIAE88, 83205)   (VIAE88, 83206)  ...  None  None  None
2564   (VIAE97, 21942)   (VIAE97, 21943)   (VIAE97, 21944)  ...  None  None  None
2565   (VIAE98, 71123)   (VIAE98, 71124)   (VIAE98, 71125)  ...  None  None  None

[2566 rows x 35406 columns]

所有 None 值都是由于最长的火车是 35406 秒长,并且 Dataframe 中的所有其他记录必须与该行的列数匹配。需要消除这些 None 值。

但现在我被困住了。我想达到的是:

         train seconds   
0        1001  21923 
1        1001  21924 
2        1001  21925
...      ...     ...
???    VIAE98  71123
???    VIAE98  71124
???    VIAE98  71125

实际上,每个单独的行都已被转置(扩展了单个列表并消除了空元素),并且所有转置的行都已连接到一个 2 列的长数据帧中。

你能帮我完成最后一步和/或给我一些其他方法来完成我最初的问题陈述(在开头用斜体字)。

非常感谢您的帮助。我非常感谢所有回答 StackOverflow 问题的人。

马克·巴顿-卡鲁

【问题讨论】:

    标签: python pandas dataframe pandas-groupby


    【解决方案1】:

    您可以使用reindex 获取每个火车组的minmax 秒数:

    def populate_df(grp):
        grp = (grp.set_index('seconds')
               .reindex(range(grp.seconds.min(), grp.seconds.max()+1))
               .drop(columns='train')
               .fillna(0)
              )
        return grp
    
    df.groupby('train').apply(populate_df).reset_index()
    

    【讨论】:

    • 效果很好,谢谢!以防万一任何未来的读者遇到我的下一个问题......不幸的是,第一次运行失败了,因为它证明我的数据(除了丢失了一些秒)有一些具有重复秒值的行,如果有,reindex 命令会失败一个重复的密钥。所以接下来我要做的是解决重复问题,然后这段代码就可以正常运行了。
    猜你喜欢
    • 1970-01-01
    • 2015-02-17
    • 1970-01-01
    • 1970-01-01
    • 2022-08-15
    • 1970-01-01
    • 2021-09-03
    • 2015-11-20
    • 1970-01-01
    相关资源
    最近更新 更多