【问题标题】:For a column in pandas dataframe, calculate mean of column values in previous 4th, 8th and 12th row from the present row?对于 pandas 数据框中的一列,计算当前行前第 4、第 8 和第 12 行的列值的平均值?
【发布时间】:2021-07-14 21:26:33
【问题描述】:

在 pandas 数据框中,我想创建一个新列来计算我们当前行之前第 4、第 8 和第 12 行的列值的平均值。

如下表所示,对于第13行:

现有列中的值,即第 13 行之前 4 行(第 9 行)= 4

现有列中的值,即第 13 行之前的 8 行(第 5 行)= 6

现有列中的值,即第 13 行(第 1 行)前 12 行 = 2

4,6,2 的平均值为 4。因此 New Column = 4 在第 13 行,对于 1-12 之间的其余行,New Column = Nan

我的 df 中有更多行,但我在此处仅添加了前 13 行以进行说明。

Row number Existing column New column
1 2 NaN
2 4 NaN
3 3 NaN
4 1 NaN
5 6 NaN
6 4 NaN
7 8 NaN
8 2 NaN
9 4 NaN
10 9 NaN
11 2 NaN
12 4 NaN
13 3 3

【问题讨论】:

  • 我的回答需要任何澄清吗?如果需要任何微调以满足您的要求,请告诉我。
  • 谢谢SeaBean!这完全符合我的要求。除了平均值之外,我如何调整这种方法以获得相同值的中位数?

标签: python pandas dataframe numpy indexing


【解决方案1】:
  1. 您可以使用rolling.apply 来应用自定义聚合函数。
  2. (4,6,2) 的平均值是 4,而不是 3
>>> (2 + 6 + 4) / 3
4.0
>>> df["New column"] = df["Existing column"].rolling(13).apply(lambda x: x.iloc[[0, 4, 8]].mean())
>>> df
    Row number  Existing column  New column
0            1                2         NaN
1            2                4         NaN
2            3                3         NaN
3            4                1         NaN
4            5                6         NaN
5            6                4         NaN
6            7                8         NaN
7            8                2         NaN
8            9                4         NaN
9           10                9         NaN
10          11                2         NaN
11          12                4         NaN
12          13                3         4.0

分解:

  • df["Existing column"]:从数据框中选择“现有列”
  • .rolling(13):从前 13 行开始,我们将在所有数据上移动一个滑动窗口。所以首先,我们会遇到第 0-12 行,然后是第 1-13 行,然后是第 2-14 行,以此类推。
  • .apply(...):对于上述每个滚动部分,我们将应用一个适用于每个部分的函数(在本例中,我们应用的函数是 lambda。
  • lambda x: x.iloc[[0, 4, 8]].mean():从每个滚动部分中提取第 0、第 4 和第 8(对应于第 1、5 和 9 行)并计算并返回这些值的平均值。

为了在块(或组)而不是滑动窗口中处理数据帧,您可以使用 .groupby 方法(而不是 .rolling)应用相同的逻辑。

>>> groups = np.arange(len(df)) // 13 # defines groups as chunks of 13 rows
>>> averages = (
        df.groupby(groups)["Existing column"]
        .apply(lambda x: x.iloc[[0, 4, 8]].mean())
    )
>>> averages.index = (averages.index + 1) * 13 - 1
>>> df["New column"] = averages
>>> df
    Row number  Existing column  New column
0            1                2         NaN
1            2                4         NaN
2            3                3         NaN
3            4                1         NaN
4            5                6         NaN
5            6                4         NaN
6            7                8         NaN
7            8                2         NaN
8            9                4         NaN
9           10                9         NaN
10          11                2         NaN
11          12                4         NaN
12          13                3         4.0

立即分解:

  • groups = np.arange(len(df)):创建一个数组,用于将我们的数据帧分块。该数组本质上是 13 个 0,然后是 13 个 1,然后是 13 个 2... 直到数组与数据帧的长度相同。因此,在这种情况下,对于单个块示例,它只会是 13 个 0 的数组。

  • df.groupby(groups)["Existing column"]根据上面定义的组对数据框进行分组并选择“现有列”

  • .apply(lambda x: x.iloc[[0, 4, 8]].mean()):概念上与之前相同,只是我们应用到每个分组而不是滑动窗口。

  • averages.index = (averages.index + 1) * 12:这部分可能看起来有点奇怪。但我们基本上确保我们选择的平均值与原始数据集正确对齐。在这种情况下,我们希望第 0 组的平均值(在averages 系列中指定索引值为 0)与第 12 行对齐。如果我们有另一个组(第 1 组,我们希望它与第 25 行对齐在原始数据集中)。所以我们可以用一点数学来做这个转换。

  • df["New column"] = averages:由于我们已经匹配了我们的索引,pandas 会在后台为我们处理这些新值的实际对齐。

【讨论】:

  • 感谢您的解决方案卡梅伦!非常感谢您在这里的帮助。但是,对于第 13 行之后的接下来的 12 行,即第 14 到第 25 行 - 我在新列中的值应该再次是 NaN,第 26 行中的值应该是第 22 行、第 18 行和第 14 行的平均值。换句话说,我有 13 行的分区,并且只能在该分区内计算第 13 行之前的第 4、第 8 和第 12 行的平均值
  • 啊,我误解了你的问题。让我编辑我的答案。
【解决方案2】:

.shift() 是您缺少的部分。我们可以使用它来访问 Pandas 数据框中现有行中的前行。

让我们使用.groupby().apply().shift()如下:

df['New column'] = df.groupby((df['Row number'] - 1) // 13)['Existing column'].apply(lambda x: (x.shift(4) + x.shift(8) + x.shift(12)) / 3)

这里,通过将行分组到(df['Row number'] - 1) // 13设置的不同组号下,将行划分为13行的组

然后在每个组内,我们在Existing column 列上使用.apply() 并使用.shift() 来获取组内之前的第4、8 和12 个条目。

试运行

data = {'Row number' : np.arange(1, 40), 'Existing column': np.arange(11, 50) }
df = pd.DataFrame(data)

print(df)

    Row number  Existing column
0            1               11
1            2               12
2            3               13
3            4               14
4            5               15
5            6               16
6            7               17
7            8               18
8            9               19
9           10               20
10          11               21
11          12               22
12          13               23
13          14               24
14          15               25
15          16               26
16          17               27
17          18               28
18          19               29
19          20               30
20          21               31
21          22               32
22          23               33
23          24               34
24          25               35
25          26               36
26          27               37
27          28               38
28          29               39
29          30               40
30          31               41
31          32               42
32          33               43
33          34               44
34          35               45
35          36               46
36          37               47
37          38               48
38          39               49

df['New column'] = df.groupby((df['Row number'] - 1) // 13)['Existing column'].apply(lambda x: (x.shift(4) + x.shift(8) + x.shift(12)) / 3)

print(df)

    Row number  Existing column  New column
0            1               11         NaN
1            2               12         NaN
2            3               13         NaN
3            4               14         NaN
4            5               15         NaN
5            6               16         NaN
6            7               17         NaN
7            8               18         NaN
8            9               19         NaN
9           10               20         NaN
10          11               21         NaN
11          12               22         NaN
12          13               23        15.0
13          14               24         NaN
14          15               25         NaN
15          16               26         NaN
16          17               27         NaN
17          18               28         NaN
18          19               29         NaN
19          20               30         NaN
20          21               31         NaN
21          22               32         NaN
22          23               33         NaN
23          24               34         NaN
24          25               35         NaN
25          26               36        28.0
26          27               37         NaN
27          28               38         NaN
28          29               39         NaN
29          30               40         NaN
30          31               41         NaN
31          32               42         NaN
32          33               43         NaN
33          34               44         NaN
34          35               45         NaN
35          36               46         NaN
36          37               47         NaN
37          38               48         NaN
38          39               49        41.0

【讨论】:

  • 谢谢SeaBean!这完全符合我的要求。除了平均值之外,我如何调整这种方法以获得相同值的中位数?
  • @srikarmalladi 要获得中位数,可以使用df['New column'] = df.groupby((df['Row number'] - 1) // 13)['Existing column'].transform(lambda x: [np.nan] * 12 + [x.iloc[[0, 4, 8]].median()]) 也可以将这段代码中的.median() 替换为.mean() 以获得均值。
  • @srikarmalladi 如果您使用我的样本数据,您可能会发现中位数和均值具有相同的值。没有问题。这是因为仅通过重合,均值和中位数具有相同的值。您可以使用其他数据集对其进行测试。
猜你喜欢
  • 2020-03-01
  • 2021-12-12
  • 2022-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-26
  • 1970-01-01
相关资源
最近更新 更多