【问题标题】:Adding missing rows of pandas DataFrame when index contains duplicate data当索引包含重复数据时,添加缺失的 pandas DataFrame 行
【发布时间】:2018-09-18 15:38:28
【问题描述】:

我有一个带有dtype=object 的DataFrame:

          YY    MM  DD  hh  var1    var2
.
.
.

10512   2013    01  01  06  1.64    4.64
10513   2013    01  01  07  1.57    4.63
10514   2013    01  01  08  1.56    4.71
10515   2013    01  01  09  1.45    4.69
10516   2013    01  01  10  1.53    4.67
10517   2013    01  01  11  1.31    4.63
10518   2013    01  01  12  1.41    4.70
10519   2013    01  01  13  1.49    4.80
10520   2013    01  01  20  1.15    4.91
10521   2013    01  01  21  1.14    4.74
10522   2013    01  01  22  1.10    4.95

正如所见,缺少对应于小时的行 (hh)(例如,在 10519 和 10520 行之间,hh 从 13 跳到 20)。我试图通过将hh 设置为索引来添加差距,正如这里讨论的那样:Missing data, insert rows in Pandas and fill with NAN

df=df.set_index('hh')
new_index = pd.Index(np.arange(0,24), name="hh")
df=df.reindex(new_index).reset_index() 

并达到类似:

          YY    MM  DD  hh  var1    var2

10519   2013    01  01  13  1.49    4.80
10520   2013    01  01  14  Nan     Nan
10521   2013    01  01  15  Nan     Nan
10522   2013    01  01  16  Nan     Nan
...
10523   2013    01  01  20  1.15    4.91
10524   2013    01  01  21  1.14    4.74
10525   2013    01  01  22  1.10    4.95

但是我遇到了df=df.reindex(new_index) 部分的错误"cannot reindex from a duplicate axis"。 每个hh=0,1,...,23 都有重复的值,因为hh 的相同值将在不同的月份(MM) 和年份(YY) 中重复。 大概就是这个原因吧。我该如何解决这个问题?

一般来说,当索引包含重复数据时,如何填充 pandas DataFrame 的缺失行。我感谢任何 cmets。

【问题讨论】:

  • 缺失数据到底在哪里,我在 10519 和 10520 之间看不到 hh 的 NaN?
  • @KhalilAlHooti 数据具有每小时分辨率,但它从 13 跳到 20。我想用 var1 和 var 2 的 Nan 值插入缺失的行(14、15、16,...)所以之后我可以使用插值等简单技术计算 Nans。

标签: python pandas dataframe


【解决方案1】:

首先创建一个新列,其中包含日期时间类型的时间,包括日期和小时。一种方法如下:

df = df.rename(columns={'YY': 'year', 'MM': 'month', 'DD': 'day', 'hh': 'hour'})
df['time'] = pd.to_datetime(df[['year', 'month', 'day', 'hour']])

要以这种方式使用to_datetime,列名需要为yearmonthdayhour,这就是使用rename 的原因。

要获得预期的结果,请将这个新列设置为索引并使用resample

df.set_index('time').resample('H').mean()

【讨论】:

  • 感谢您的宝贵时间。它解决了这个问题。唯一的问题是 dtype 需要是数字,而不是可以轻松更改的对象。
  • @PierreHoshyar:乐于助人。是的,实际上要使用resample 方法,列本身需要是数字的,但是可以通过使用agg 而不是mean 来解决,请参阅stackoverflow.com/questions/47613521/…
【解决方案2】:

这段代码完全符合您的需要。

import pandas as pd
import numpy as np
from io import StringIO

YY, MM, DD, hh, var1, var2 = [],[],[],[],[],[]


a = '''10512   2013    01  01  06  1.64    4.64
10513   2013    01  01  07  1.57    4.63
10514   2013    01  01  08  1.56    4.71
10515   2013    01  01  09  1.45    4.69
10516   2013    01  01  10  1.53    4.67
10517   2013    01  01  11  1.31    4.63
10518   2013    01  01  12  1.41    4.70
10519   2013    01  01  13  1.49    4.80
10520   2013    01  01  20  1.15    4.91
10521   2013    01  01  21  1.14    4.74
10522   2013    01  01  22  1.10    4.95
10523   2013    01  01  27  1.30    4.55
10524   2013    01  01  28  1.2     4.62
'''

text = StringIO(a)

for line in text.readlines():
    a = line.strip().split(" ")
    a = list(filter(None, a))
    YY.append(a[1])
    MM.append(a[2])
    DD.append(a[3])
    hh.append(a[4])
    var1.append(a[5])
    var2.append(a[6])

df = pd.DataFrame({'YY':YY, 'MM':MM, 'DD':DD,
                   'hh':hh, 'var1':var1, 'var2':var2})

df['hh'] = df.hh.astype(int)


a = np.diff(df.hh)
b = np.where(a!=1)


df2 = df.copy(deep=True)

for i in range(len(df)):

    if (i in b[0]):
        line = pd.DataFrame(columns=['YY', 'MM', 'DD',
                                     'hh', 'var1', 'var2'])
        for k in range(a[i]-1):

            line.loc[k]=[df2.iloc[i, 0], df2.iloc[i, 1],
                         df2.iloc[i, 2], df2.iloc[i, 3]+k+1 ,
                         np.nan, np.nan]

        df = pd.concat([df.loc[:i], 
                line, df.loc[i+1:]])


df.reset_index(inplace=True, drop=True)

print(df)

      YY  MM  DD  hh  var1  var2
0   2013  01  01   6  1.64  4.64
1   2013  01  01   7  1.57  4.63
2   2013  01  01   8  1.56  4.71
3   2013  01  01   9  1.45  4.69
4   2013  01  01  10  1.53  4.67
5   2013  01  01  11  1.31  4.63
6   2013  01  01  12  1.41  4.70
7   2013  01  01  13  1.49  4.80
8   2013  01  01  14   NaN   NaN
9   2013  01  01  15   NaN   NaN
10  2013  01  01  16   NaN   NaN
11  2013  01  01  17   NaN   NaN
12  2013  01  01  18   NaN   NaN
13  2013  01  01  19   NaN   NaN
14  2013  01  01  20  1.15  4.91
15  2013  01  01  21  1.14  4.74
16  2013  01  01  22  1.10  4.95
17  2013  01  01  23   NaN   NaN
18  2013  01  01  24   NaN   NaN
19  2013  01  01  25   NaN   NaN
20  2013  01  01  26   NaN   NaN
21  2013  01  01  27  1.30  4.55
22  2013  01  01  28   1.2  4.62

【讨论】:

  • 感谢您的宝贵时间。这也有效。只是出于好奇,当 DataFrame 非常正确时,那些 for 循环可能会很耗时?
  • 可能是的。内部 for 循环是最耗时的,尤其是在缺少许多样本的情况下。代码还有另一个缺点。例如,如果连续几天之间缺少小时数据,则代码将不起作用,除非在 for 循环之前应用每天分组,这很容易做到。
  • 是的,您的意思是没有超过一天的小时样本。我想到了这一点,但我认为数据不是空的超过几个小时。感谢您的宝贵时间。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-11
  • 2017-12-22
  • 2022-01-09
  • 2021-05-07
  • 1970-01-01
  • 2018-01-18
  • 2015-05-14
相关资源
最近更新 更多