Python:遍历数据框列,检查存储在数组中的条件值,并将值获取到列表中

Posted

技术标签:

【中文标题】Python:遍历数据框列,检查存储在数组中的条件值,并将值获取到列表中【英文标题】:Python: Iterate over a data frame column, check for a condition-value stored in array, and get the values to a list 【发布时间】:2017-05-23 14:11:21 【问题描述】:

在论坛获得一些帮助后,我设法完成了我正在寻找的事情,现在我需要更上一层楼。 (长解释在这里: Python Data Frame: cumulative sum of column until condition is reached and return the index):

我有一个数据框:

In [3]: df
Out[3]: 
   index  Num_Albums  Num_authors
0      0          10            4
1      1           1            5
2      2           4            4
3      3           7         1000
4      4           1           44
5      5           3            8

我用另一列的累积和添加一列。

In [4]: df['cumsum'] = df['Num_Albums'].cumsum()

In [5]: df
Out[5]: 
   index  Num_Albums  Num_authors  cumsum
0      0          10            4      10
1      1           1            5      11
2      2           4            4      15
3      3           7         1000      22
4      4           1           44      23
5      5           3            8      26

然后我将条件应用于cumsumcolumn 并提取满足条件且具有给定容差的行的相应值:

In [18]: tol = 2

In [19]: cond = df.where((df['cumsum']>=15-tol)&(df['cumsum']<=15+tol)).dropna()

In [20]: cond
Out[20]: 
   index  Num_Albums  Num_authors  cumsum
2    2.0         4.0          4.0    15.0

现在,我要做的是将示例中的条件15 替换为存储在数组中的条件。检查何时满足条件并且不检索整行,而仅检索列Num_Albums 的值。最后,所有这些检索到的值(每个条件一个)都存储在数组或列表中。 来自 matlab,我会做这样的事情(我为这种混合的 matlab/python 语法道歉):

conditions = np.array([10, 15, 23])
for i=0:len(conditions)
   retrieved_values(i) = df.where((df['cumsum']>=conditions(i)-tol)&(df['cumsum']<=conditions(i)+tol)).dropna()

所以对于上面的数据框,我会得到(tol=0):

retrieved_values = [10, 4, 1]

如果可能的话,我想要一个让我保留.where 功能的解决方案..

【问题讨论】:

【参考方案1】:

一种快速的方法是利用 NumPy 的广播技术作为同一帖子链接中 this answer 的扩展,尽管实际上有人询问了与使用 DF.where 相关的答案。

广播消除了遍历数组的每个元素的需要,同时它非常高效。

对这篇文章的唯一补充是使用np.argmax 来获取沿每列的第一个True 实例的索引(遍历↓ 方向)。

conditions = np.array([10, 15, 23])
tol = 0
num_albums = df.Num_Albums.values
num_albums_cumsum = df.Num_Albums.cumsum().values
slices = np.argmax(np.isclose(num_albums_cumsum[:, None], conditions, atol=tol), axis=0)

检索到的切片:

slices
Out[692]:
array([0, 2, 4], dtype=int64)

产生的对应数组:

num_albums[slices]
Out[693]:
array([10,  4,  1], dtype=int64)

如果您仍然喜欢使用DF.where,这里是使用list-comprehension 的另一种解决方案-

[df.where((df['cumsum'] >= cond - tol) & (df['cumsum'] <= cond + tol), -1)['Num_Albums']
   .max() for cond in conditions]
Out[695]:
[10, 4, 1]

不满足给定条件的条件将被替换为 -1。这样做会在末尾保留dtype

【讨论】:

我其实更喜欢第一个选项。我不确定“无”的使用对我来说是否清楚。我通过应用您的建议得到的是,当条件不满足时,“切片”假定值为 0。当我调用“num_albums [切片]”时,我得到条件为的每个位置的第一个值(在索引 0 处)不满足..当条件不满足时,如何让“切片”为 NaN? None 这里暗示了np.newaxis,简单来说就是对数组进行整形,以便在其中插入一个额外的维度,这允许我们查询那么多维度的数组(这里,2- D 数组)。出于同样的目的,num_albums_cumsum.reshape(-1, 1) 也可以使用。不,num_albums[slices] 为您提供满足条件的值。如果您希望NaN's 出现在False 条件下,那么我建议您改为考虑np.where。但我不明白它的含义,因为您只想在列表/数组中获取它们。【参考方案2】:

输出并不总是 1 个数字,对吧? 如果输出是精确的 1 数字,您可以编写此代码

tol = 0
#condition
c = [5,15,25]
value = []

for i in c:
    if len(df.where((df['a'] >= i - tol) & (df['a'] <= i + tol)).dropna()['a']) > 0:
        value = value + [df.where((df['a'] >= i - tol) & (df['a'] <= i + tol)).dropna()['a'].values[0]]
    else:
        value = value + [[]]
print(value)

输出应该是这样的

[1,2,3]

如果输出可以是多个数字并且想要这样

[[1.0, 5.0], [12.0, 15.0], [25.0]]

您可以使用此代码

tol = 5
c = [5,15,25]
value = []

for i in c:
    getdatas = df.where((df['a'] >= i - tol) & (df['a'] <= i + tol)).dropna()['a'].values
    value.append([x for x in getdatas])
print(value)

【讨论】:

我不断收到这个:IndexError: index 0 is out of bounds for axis 0 with size 0 @Amaz 是第一选择还是第二选择?第一个将是 indexError,因为它需要 .values[0],需要事先验证,让我为您编辑它

以上是关于Python:遍历数据框列,检查存储在数组中的条件值,并将值获取到列表中的主要内容,如果未能解决你的问题,请参考以下文章

如何检查同一数据框列中的重复值并通过根据频率删除行来应用 if 条件?

python遍历数据框列

python区分数据框列的'300'和'300.0'

检查数据框列中的所有值是不是相同

使用 $ 和字符值动态选择数据框列

使用 $ 和字符值动态选择数据框列