Почему я не могу присвоить значение, используя loc, когда на фрейме данных есть смешанные типы данных? т.е. в некоторых столбцах есть строки, в других есть номера - PullRequest
0 голосов
/ 07 июня 2019

Я использую pandas dataframe в Python 3.6 для индексирования файлов и атрибутов. Мое первоначальное решение использует имена файлов в первом столбце кадра данных и числовые атрибуты в других столбцах.

Когда я перебираю файлы, собирающие атрибуты, и пытаюсь присвоить значения соответствующему столбцу на фрейме данных, значения не сохраняются должным образом.

Я сделал несколько попыток и, наконец, получил работающий код, но я не понимаю, почему первоначальное решение не сработало.

Может ли кто-нибудь дать какое-то объяснение или, возможно, лучшее решение для присвоения значений элементам в кадре данных, которые не вызывают аварийные сигналы. (Я знаю, как отключить сигнализацию в этом случае, но я бы не стал этого делать)

Проблема иллюстрируется следующим кодом. Я получаю те же результаты, если фрейм данных создается по-разному, а также если столбец со строковым значением находится на разных позициях, например второй или третий столбец на фрейме данных.

Не пытался использовать другие типы данных, такие как bool, но я думаю, что проблема связана с фреймами данных со смешанными типами данных в целом.

#!/usr/bin/python3

# Import standard libraries
import pandas as pd
import numpy as np

# constants used as label for harmonization with the HDF5 ontology used
ROW_LENGTH = 11
COL1 = 'x1'
COL2 = 'x2'
COL3 = 'x3'

def _main():

    # Create a dataframe
    first_df = pd.DataFrame(columns=[COL1, COL2, COL3])
    first_df[COL1] = ["foo"]*ROW_LENGTH
    first_df[COL2] = [np.NaN]*ROW_LENGTH
    first_df[COL3] = [np.NaN]*ROW_LENGTH

    # Go around assigning data
    for row in range(ROW_LENGTH):
        first_df[COL1][row] = "{}".format(row)
        first_df[COL2][row] = row*2 # Although it gives warning, it works
        first_df.loc[row][COL3] = row*3 # And this, that should work, don't

    print("Although no data was not stored on the third column using: first_df.loc[row][COL3]")
    print(first_df.head())
    print("\n...I can retrieve the data like: first_df[COL2][5] = '{}'".format(first_df[COL2][3]))
    print("... or like that: first_df.loc[5][COL2] = '{}'".format(first_df.loc[3][COL2]))

    # If the first row is numeric...
    second_df = pd.DataFrame(columns=[COL1, COL2, COL3])
    second_df[COL1] = [0.0]*ROW_LENGTH
    second_df[COL2] = [0.0]*ROW_LENGTH
    second_df[COL3] = [0.0]*ROW_LENGTH

    # Go around assigning data
    for row in range(ROW_LENGTH):
        second_df[COL1][row] = row*1.0
        second_df[COL2][row] = row*2.0
        second_df.loc[row][COL3] = row*3.0

    print("\nNow if I use only numeric columns, everything works as expected:")
    print(second_df.head())

if __name__ == '__main__':
    _main()

Вывод:

Although no data was not stored on the third column using: first_df.loc[row][COL3]
  x1   x2  x3
0  0  0.0 NaN
1  1  2.0 NaN
2  2  4.0 NaN
3  3  6.0 NaN
4  4  8.0 NaN

...I can retrieve the data like: first_df[COL2][5] = '6.0'
... or like that: first_df.loc[5][COL2] = '6.0'

Now if I use only numeric columns, everything works as expected:
    x1   x2    x3
0  0.0  0.0   0.0
1  1.0  2.0   3.0
2  2.0  4.0   6.0
3  3.0  6.0   9.0
4  4.0  8.0  12.0

Предупреждающее сообщение такое

./test.py:24: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
  first_df[COL2][row] = row*2 # Although it gives warning, it works

Это предупреждение можно отключить, используя: pd.options.mode.chained_assignment = None

Я полагаю, что код самообъяснимо относительно ожидаемых результатов, но вкратце я хотел бы получить доступ к любому элементу, используя метод .loc.

1 Ответ

1 голос
/ 07 июня 2019

Используйте first_df.loc[row, COL3] вместо first_df.loc[row][COL3].

Когда вы используете first_df.loc[row][COL3], вы сначала создаете временную серию с first_df.loc[row], затем получаете доступ и изменяете значение в COL3 и удаляетеэто временная серия.Эквивалентно:

tmp = first_df.loc[row]
tmp[COL3] = row*3

И tmp никогда не выполняет обратную запись в исходный кадр данных.

...