Изменение значений в панде датафрейм не работает
Im имеет проблему изменения значений в кадре данных. Я также хочу посоветоваться с проблемой, которую мне нужно решить, и правильным способом использования 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 (его довольно легко реализовать на регулярном питоне, но для его выполнения потребуется много циклов и структурирования данных, что, по моему мнению, значительно замедлит процесс, а также Я использую этот процесс, чтобы более глубоко изучить способности pandas)
Я вышел со следующим решением. В качестве этапов подготовки, Ill группирует имя динамика и задает имя файла как индекс методом set_index. Затем я переберу группу groupObj и примените функцию вычисления, которая вернет выбранный динамик и файлы, которые будут помечены как используемые.
Затем Ill перебирайте файлы и помечайте их как используемые (это было бы быстрым и простым, поскольку я заранее задавал их как индексы) и так далее, пока не закончу вычисление.
Во-первых, я не уверен в этом решении, поэтому не стесняйтесь рассказывать мне свои мысли об этом.
Теперь я попытался реализовать это и попал в беду:
Сначала я проиндексирован по имени файла, здесь нет проблем:
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
Итак, вы видите проблему. Ничего не изменилось. Что я делаю не так? Описанная выше проблема должна быть решена с помощью pandas?
А также:
1. Как я могу подойти к определенной группе с помощью объекта groupby? bcz Я думал, может быть, вместо того, чтобы устанавливать файлы как индексированные, группируя по файлу, и используя эту группу, чтобы obj применить изменяющуюся функцию ко всем ее вхождениям. Но я не нашел способ приблизиться к определенной группе и передать имя группы в качестве параметра и вызвать действие применительно ко всем группам, а затем действовать только на одном из них, казалось, не "правильно" для меня.
Надеюсь, это не долго...:)
Ответы
Ответ 1
Индексирование объектов 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
, которое, я думаю, может быть ближе к тому, что вы действительно хотите.
Джефф уже предоставил ссылку в Pandas docs, в которой указано, что
Правила о том, когда возвращается представление данных, полностью зависит от 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