python pandas 在列块上使用逻辑运算符

0 投票
1 回答
967 浏览
提问于 2025-04-18 12:06

我有一个数据集,已经加载到一个叫做 pandas 的数据框里,内容大致如下:

n=2
np.random.seed(1)
dt = pd.DataFrame((np.random.rand(5, 2*n+1)*1000).round(), columns=['id', 'x_0', 'y_0', 'x_1', 'y_1'])
>>> dt
    id  x_0  y_0  x_1  y_1
0  417  720    0  302  147
1   92  186  346  397  539
2  419  685  204  878   27
3  670  417  559  140  198
4  801  968  313  692  876

[5 rows x 5 columns]

我知道这个方法只适用于 n=2 的情况,但现在我还不知道如何为其他 n 值构建列名(不过我想这可能是另一个话题的问题)。

一般来说,我可以有 n 组 x 和 y 列(这些是按月的数据)。

我需要做的是检查在同一个月里,x_i 和 y_i 的值是否都超过了某个特定的数值,如果在任何一个 n 个月里都超过了,就返回 1,否则返回 0。

所以,我正在尝试:

>>> (dt[range(1, 2*n+1, 2)] > 400)
     x_0    x_1
0   True  False
1  False  False
2   True   True
3   True  False
4   True   True

[5 rows x 2 columns]
>>> (dt[range(2, 2*n+1, 2)] > 300)
     y_0    y_1
0  False  False
1   True   True
2  False  False
3   True  False
4   True   True

[5 rows x 2 columns]

在这里,我想检查 x_i 的值是否超过 400,以及 y_i 是否超过 300。这样会产生两个包含 x 和 y 值的数据框(宽度为 n 列),这没问题。但是当我尝试:

(dt[range(1, 2*n+1, 2)] > 400) & (dt[range(2, 2*n+1, 2)] > 300)

它并没有逐个元素应用 & 操作符,而是返回了一个包含 NaN 的 2*n 数据框:

   x_0  x_1  y_0  y_1
0  NaN  NaN  NaN  NaN
1  NaN  NaN  NaN  NaN
2  NaN  NaN  NaN  NaN
3  NaN  NaN  NaN  NaN
4  NaN  NaN  NaN  NaN

我显然在这里漏掉了什么。我的问题是,这背后的逻辑是什么,以及如何让它正常工作。

如果我能让这个工作,我会尝试使用 any() 函数和 apply() 方法。

任何建议都很受欢迎。

*编辑 这里还有一个 R 语言的代码片段,可以解决这个问题。也许 R 的方法让我在 Python 代码上感到“负担”。

> n=2
> dt <- data.frame(id = c(417, 92, 419, 670, 801),
+                     x_0 = c(720, 186, 685, 417, 968),
+                     y_0 = c(0, 346, 204, 559, 313),
+                     x_1 = c(302, 397, 878, 140, 692),
+                     y_1 = c(147, 539, 27, 198, 876))

> (x <- (dt[,seq(2, 2*n+1, by=2)] > 400) & (dt[,seq(3, 2*n+1, by=2)] > 300))
       x_0   x_1
[1,] FALSE FALSE
[2,] FALSE FALSE
[3,] FALSE FALSE
[4,]  TRUE FALSE
[5,]  TRUE  TRUE
> (result <- apply(x, 1, any, na.rm=T))
[1] FALSE FALSE FALSE  TRUE  TRUE

1 个回答

0

这个方法是通过列名来进行索引的,而不是在列上使用逻辑运算符。它是通过一个叫做apply的函数来逐行处理数据的:

n=2
import numpy as np
import pandas as pd

dt = pd.DataFrame((np.random.rand(5, 2*n+1)*1000).round(), columns=['id', 'x_0', 'y_0', 'x_1', 'y_1'])
print dt

def check_x(x):
    value=0
    columns_with_x = [col for col in x.index if 'x_' in col]
    columns_with_y = [col for col in x.index if 'y_' in col]
    for each_col_x in columns_with_x:
        if x[each_col_x] > 400:
            for each_col_y in columns_with_y:
                if x[each_col_y] > 300:
                    value=1
    return value

checked = dt.apply(check_x, axis=1)

print checked

输出结果:

    id  x_0  y_0  x_1  y_1
0  251  525  976  743  206
1  324  354  238  413   93
2   21  999  731  416  431
3  652  926  131  510  627
4  124  387  747  972  678

0    1
1    0
2    1
3    1
4    1
dtype: int64

撰写回答