10

我在更改数据框中的值时遇到问题。我也想咨询一下我需要解决的问题以及使用 pandas 解决它的正确方法。我会很感激这两个方面的帮助。我有一个文件,其中包含有关音频文件与扬声器匹配程度的信息。该文件看起来像这样:

wave_path   spk_name    spk_example#    score   mark    comments    isUsed
190  122_65_02.04.51.800.wav     idoD    idoD    88  NaN     NaN     False
191  121_110_20.17.27.400.wav    idoD    idoD    87  NaN     NaN     False
192  121_111_00.34.57.300.wav    idoD    idoD    87  NaN     NaN     False
193  103_31_18.59.12.800.wav     idoD    idoD_0  99  HIT     VP  False
194  131_101_02.08.06.500.wav    idoD    idoD_0  96  HIT     VP  False

我需要做的是某种复杂的计数。我需要按扬声器对结果进行分组,并为每个扬声器计算一些计算。然后我继续使用为我进行最佳计算的扬声器,但在继续之前,我需要将用于计算的所有文件标记为正在使用,即更改它们出现的每一行的 isUsed 值(文件可以出现不止一次)为真。然后我再做一次迭代。计算每个扬声器,标记使用的文件等,直到没有更多的扬声器需要计算。

我对如何使用 pandas 实现该过程进行了很多思考(在常规 python 中实现很容易,但需要大量循环和数据结构,我的猜测会显着减慢过程,而且我正在使用这个更深入地学习熊猫能力的过程)

我提出了以下解决方案。作为准备步骤,我将按扬声器名称分组,并通过 set_index 方法将文件名设置为索引。然后,我将遍历 groupbyObj 并应用计算函数,该函数将返回选定的扬声器和要标记为已使用的文件。

然后我将遍历文件并将它们标记为已使用(这将是快速和简单的,因为我事先将它们设置为索引),依此类推,直到我完成计算。

首先,我不确定这个解决方案,所以请随时告诉我你的想法。现在,我尝试实现这一点,但遇到了麻烦:

首先我按文件名索引,这里没问题:

In [53]:

    marked_results['isUsed'] = False
    ind_res = marked_results.set_index('wave_path')
    ind_res.head()

Out[53]:
    spk_name    spk_example#    score   mark    comments    isUsed
    wave_path                       
    103_31_18.59.12.800.wav      idoD    idoD    99  HIT     VP  False
    131_101_02.08.06.500.wav     idoD    idoD    99  HIT     VP  False
    144_35_22.46.38.700.wav      idoD    idoD    96  HIT     VP  False
    41_09_17.10.11.700.wav       idoD    idoD    93  HIT     TEST    False
    122_188_03.19.20.400.wav     idoD    idoD    93  NaN     NaN     False

然后我选择一个文件并检查我是否获得了与该文件相关的条目:

In [54]:

    example_file = ind_res.index[0];
    ind_res.ix[example_file]

Out[54]:
    spk_name    spk_example#    score   mark    comments    isUsed
    wave_path                       
    103_31_18.59.12.800.wav  idoD    idoD    99  HIT     VP  False
    103_31_18.59.12.800.wav  idoD    idoD_0  99  HIT     VP  False
    103_31_18.59.12.800.wav  idoD    idoD_1  97  HIT     VP  False
    103_31_18.59.12.800.wav  idoD    idoD_2  95  HIT     VP  False

现在这里也有问题。然后我尝试将该文件的 isUsed 值更改为 True,这就是我遇到问题的地方:

In [56]:

    ind_res.ix[example_file]['isUsed'] = True
    ind_res.ix[example_file].isUsed = True
    ind_res.ix[example_file]
Out[56]:
    spk_name    spk_example#    score   mark    comments    isUsed
    wave_path                       
    103_31_18.59.12.800.wav  idoD    idoD    99  HIT     VP  False
    103_31_18.59.12.800.wav  idoD    idoD_0  99  HIT     VP  False
    103_31_18.59.12.800.wav  idoD    idoD_1  97  HIT     VP  False
    103_31_18.59.12.800.wav  idoD    idoD_2  95  HIT     VP  False

所以,你看到了问题。什么也没有变。我究竟做错了什么?上面描述的问题应该用熊猫来解决吗?

还有: 1. 如何通过 groupby 对象接近特定组?bcz 我想也许不是将文件设置为索引,按文件分组,并使用该 groupby obj 将更改函数应用于其所有出现。但是我没有找到一种方法来接近特定组并将组名作为参数传递并在所有组上调用 apply 然后只对其中一个组采取行动对我来说似乎不“正确”。

我希望它不会太长...... :)

4

1 回答 1

22

索引 Panda 对象可以返回两个根本不同的对象:视图或副本。

如果mask是基本切片,则df.ix[mask]返回的视图df视图与原始对象 ( ) 共享相同的基础数据df。所以修改视图,也修改了原来的对象。

如果mask是更复杂的东西,例如任意索引序列df.ix[mask]返回. 修改副本对原件没有影响。df

在您的情况下,由于共享相同的行wave_path出现在任意位置,因此ind_res.ix[example_file]返回一个副本。所以

ind_res.ix[example_file]['isUsed'] = True

对 没有影响ind_res

相反,您可以使用

ind_res.ix[example_file, 'isUsed'] = True

修改ind_res. 但是,请参阅下面的groupby建议,我认为它可能更接近您真正想要的。

Jeff 已经提供了指向 Pandas 文档的链接,其中指出

关于何时返回数据视图的规则完全取决于 NumPy。

以下是描述何时返回视图或副本的(复杂的)规则。然而,基本上,规则是如果索引请求底层数组的规则间隔切片,则返回视图,否则返回副本(非必要)。


这是一个使用基本切片的简单示例。视图由 返回df.ix,因此修改subdf也会修改df

import pandas as pd
import numpy as np

df = pd.DataFrame(np.arange(12).reshape(4,3), 
         columns=list('ABC'), index=[0,1,2,3])

subdf = df.ix[0]
print(subdf.values)
# [0 1 2]
subdf.values[0] = 100
print(subdf)
# A    100
# B      1
# C      2
# Name: 0, dtype: int32

print(df)           # df is modified
#      A   B   C
# 0  100   1   2
# 1    3   4   5
# 2    6   7   8
# 3    9  10  11

这是一个使用“花式索引”(选择任意行)的简单示例。副本由df.ix. 所以修改subdf不影响df

df = pd.DataFrame(np.arange(12).reshape(4,3), 
         columns=list('ABC'), index=[0,1,0,3])

subdf = df.ix[0]
print(subdf.values)
# [[0 1 2]
#  [6 7 8]]

subdf.values[0] = 100
print(subdf)
#      A    B    C
# 0  100  100  100
# 0    6    7    8

print(df)          # df is NOT modified
#    A   B   C
# 0  0   1   2
# 1  3   4   5
# 0  6   7   8
# 3  9  10  11

请注意,这两个示例之间的唯一区别是,在第一个示例中,返回视图的索引为 [0,1,2,3],而在第二个示例中,返回副本的索引为 [0, 1,0,3]。

由于我们选择了索引为 0 的行,因此在第一个示例中,我们可以使用基本切片来执行此操作。在第二个示例中,索引等于 0 的行可能出现在任意位置,因此必须返回一个副本。


尽管我对 Pandas/NumPy 切片的微妙之处大加指责,但我真的不这么认为

ind_res.ix[example_file, 'isUsed'] = True

是您最终要寻找的。你可能想做一些更像

import pandas as pd
import numpy as np

df = pd.DataFrame(np.arange(12).reshape(4,3), 
                  columns=list('ABC'))
df['A'] = df['A']%2
print(df)
#    A   B   C
# 0  0   1   2
# 1  1   4   5
# 2  0   7   8
# 3  1  10  11

def calculation(grp):
    grp['C'] = True
    return grp

newdf = df.groupby('A').apply(calculation)
print(newdf)

产生

   A   B     C
0  0   1  True
1  1   4  True
2  0   7  True
3  1  10  True
于 2013-08-01T14:13:36.833 回答