Ответы пользователя по тегу Pandas
  • Как исправить ошибку при использовании pandas concat?

    Maksim_64
    @Maksim_64
    Data Analyst
    1. Почему не работает. Потому что concat принимает список с фреймами или series'ами. Твой объект это список с кортежами, а должен быть список с фреймами.
    Раньше, я так понимаю ты использовал пустой датафрейм и к нему в цикле конкатенировал словарь. Если раньше твой код работал то и сейчас ты можешь собрать список словарей и создать из них фрейм. Например
    d1 = {'A':1,'B':2}
    d2 = {'A':3,'B':4}
    df = pd.DataFrame.from_records([d1,d2])
    собирашь в список словари и по этом передаешь методу from_records. Это вместо concat. Если хочется работать с concat. То при каждой итерации ты создаешь отдельный фрейм с данными и одинаковыми колонками, собираешь эти фреймы в список и потом concat будет прекрасно работать например.
    dfs = []
    for i in range(3):
        df = pd.DataFrame({
            'A':np.random.randn(4),
            'B':np.random.choice(['green','blue','white'], 4)
        })
        dfs.append(df)
    final_df = pd.concat(dfs,ignore_index=True)

    Принцип должен быть тебе понятен, естественно со своими данными реализуй.
    Ответ написан
    Комментировать
  • Как выбрать правильно выбрать период в pandas?

    Maksim_64
    @Maksim_64
    Data Analyst
    Ну во первых ты не представил игрушечного датафрейма (входные данные), и каков желаемый результат (выходные данные).

    Вместо этого ты дал фрагмент кода не связанного с проблемой по всей видимости код был написан chatGPT, по скольку он очень низкого качества и попросту странный очень на вряд ли даже начинающий программист напишет такой pandas код.

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

    import pandas as pd
    import numpy as np
    
    df = pd.DataFrame({
        'temperature':[
            1.5,1,4,-2,1,-1,-1,4,3,2,1,-2,-3,-4,-5,-6,-1,2,-2,-2,-3,4,-5,-3,3,1,2,5,3,2
        ]
    }, index = pd.date_range('2023-01-01', periods=30))
    
    
    negative_groups = (
        df
        .query('temperature < 0')
        .groupby((df.temperature > 0).cumsum())
    )
    positive_groups = (
            df
            .query('temperature >= 0')
            .groupby((df.temperature < 0).cumsum())
    )
    start_date = [value for value in negative_groups.groups.values() if len(value) >=5][0][4]
    end_date = [value for value in positive_groups.groups.values() if len(value) >=5][0][4]
    
    df.loc[start_date:end_date]


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

    Заметь, если у нас например 6 повторяющихся отрицательных элементов то он он возьмет дату 5 так как по условию если 5 то начало зимы и если 5 то конец.

    Ну распечатай фрейм и распечатай выборку подсета из фрейма и убедишься, что работает правильно. Бери мой пример и прикручивай его к своим данным. Не забудь дату поставить в индекс и не забудь что бы у даты был тип данных date а не object.
    Ответ написан
  • Как отсортировать значение по группам?

    Maksim_64
    @Maksim_64
    Data Analyst
    Ну смотри скажу прямо задачка для общего кейса безнадежная надо менять вводные, потому что с одной стороны мы можем создать категории например ОГСЭ но затем у них еще и индексы 01, 02 и т.д., для того куска что ты дал я сделал, ну как общее решение это надо на уровне дизайна проблемы решать.
    cat = pd.Categorical(df['Шифр дисциплины'].str.split('.').str[0], 
    categories=['ОГСЭ','ЕН','ОПЦ','МДК','УП','ПМ','ПП'])
    print(df
     .groupby(cat)
     .apply(lambda x: x.sort_values('Шифр дисциплины', key = lambda x: x.str.split('.').str[1]))
     .reset_index(drop=True)
    )

    По решению, трюк следующий, создаем категории, они имеют порядок индекс. Когда, мы группируем groupby он СОРТИРУЕТ по умолчанию, и затем мы сортируем снова. То есть хитрость в том что бы впихнуть двойную сортировку, сначала по категориям а потом по цифрам внутри каждой категории.

    Кстати имей ввиду во второй своей попытке ты был на правильном направлении и задачка вполне себе типичная, только вместо твоего кода надо писать вот так
    cat = pd.Categorical(df['Шифр дисциплины'].str.split('.').str[0], 
    categories=['ОГСЭ','ЕН','ОПЦ','МДК','УП','ПМ','ПП'])
    df.sort_values(by=['Шифр дисциплины'],key= lambda x: cat)
    Результат будет, как у тебя только кода меньше и без всяких созданий временных колонок.

    Но повторюсь, для общего кейса на уровне дизайна надо работать, такие сложные парсинги внутри колонок это плохо. Pandas он конечно может все (что помещается в память) но лучше для полезных задач его использовать.
    Ответ написан
    2 комментария
  • Как удалить нумерацию и пустую строку в excel pandas?

    Maksim_64
    @Maksim_64
    Data Analyst
    Из коробки решения нет не для одной из твоих проблем. Ему нужен индекс, для того что бы сохранять иерархическую структуру.

    Можно ли это обойти, ну в программировании можно много чего обойти, вопрос а НУЖНО ли это, так или иначе, если хочется НЕНУЖНЫХ изобретений, то можно разбить проблему на две части отдельно писать иерархический header, отдельно данные, чего я бы на практике я не делал (чревато тем что, таблица "сдвинется куда нибудь") и вот тогда действительно проблематично.

    Удалить только пропущенную строку можно "относительно" безопасно.
    def write(df, xl_writer, startrow = 0,**kwargs):
       
        df.drop(df.index).to_excel(xl_writer, startrow = startrow,**kwargs)
        df.to_excel(xl_writer, startrow = startrow + 1,header = False,**kwargs)
        
    writer = pd.ExcelWriter("test_only_removed_empty_row.xlsx",engine='xlsxwriter')
    write(df, writer, sheet_name = 'Лист1')
    writer.close()

    Это более менее безопасно, удаление индекса все еще возможно, но приходится начинать ловить сдвиги, для общего случая ТАК ДЕЛАТЬ НЕЛЬЗЯ. Так или иначе, ужасная функция которая сделает это вот
    def write(df, xl_writer, startrow = 0,startcol=0,**kwargs):
       
        df.drop(df.index).to_excel(xl_writer, startrow = startrow,startcol=startcol,**kwargs)
        df.droplevel(0,axis=1).to_excel(xl_writer, startrow = startrow + 2, startcol=startcol+1,header = False,index=False,**kwargs)
        
    writer = pd.ExcelWriter("bad_practice.xlsx",engine='xlsxwriter')
    write(df, writer, sheet_name = 'Лист1')
    writer.close()


    Ну и в завершение, повторюсь, написание иерархических колонок, без индекса (index=False). Попросту выдает ошибку NotImplemented (Это не поддерживается текущим API). А вот такие "решения", как я продемонстрировал сомнительны. И да возможно, если не уставлен, придется установить xlsxwriter, или убрать параметр engine, что бы он использовал свой, там openpyxl по умолчанию стоит.
    Ответ написан
    Комментировать
  • Как заменить только отличные значения с помощью pandas?

    Maksim_64
    @Maksim_64
    Data Analyst
    В общем ждать ответа, на мой комментарий времени нет, если замена всегда одинаковая то вот так.
    import pandas as pd
    import numpy as np
    pd.DataFrame(np.where(dataframe_1 != dataframe_2, 'Ваше значение',dataframe_1), columns = dataframe_1.columns)


    если значения которые отличаются нужно выбрать из второго датафрейма то вот так.
    import pandas as pd
    import numpy as np
    pd.DataFrame(np.where(dataframe_1 != dataframe_2, dataframe_2,dataframe_1), columns = dataframe_1.columns)
    Ответ написан
  • Как правильно сгенерировать дату в Pandas?

    Maksim_64
    @Maksim_64
    Data Analyst
    Ну смотри, первое ты говоришь количество строк 90, при этом формируешь временную последовательность, на 90 дней при этом у тебя есть желание иметь данные с повторяющемеся днями по количеству артистов их их песен, в примере ты приводишь 3 артиста по 3 песни на каждые то есть 9 ЗАПИСЕЙ на каждый день или 90 * 9 = 810 СТРОК.

    Второе ты показываешь желаемый результат для одно дня только надо так делать для временной последовательности. И в нем собственно ты и подтверждаешь, мою мысль выше. Что строчек, будет больше чем 90.

    Код, конечно я написал, грязноват он можно подправить конечно, я на это время тратить не буду.

    import pandas as pd
    import numpy as np
    
    songs = {
        'ANNA ASTI': ['Девочка танцуй','Грустный дэнс','Гармония'],
        'Три дня дождя': ['Демоны','Где ты','Перезаряжай'],
        'MACAN': ['Кино','Пополам','Бенз'],
    }
    
    NUMBER_OF_DAYS = 3
    LENGTH_OF_FINAL_FRAME = sum(len(value) for value in (songs.values())) * NUMBER_OF_DAYS
    
    dates = pd.date_range('2023-01-01', periods=NUMBER_OF_DAYS, freq='1D')
    
    artists = []
    for key, value in songs.items():
        artists += [key] * len(value)
    
    dates_and_artists = []
    for date in dates:
        for artist in artists:
            dates_and_artists.append((date,artist))
    
    songs_arr = np.array(list(songs.values()) * NUMBER_OF_DAYS).reshape(-1,1)
    
    
    
    
    data = np.concatenate([np.array(dates_and_artists), 
                           songs_arr, 
                           np.random.randint(3000,1_000_000,LENGTH_OF_FINAL_FRAME).reshape(-1,1)], axis=1)
    
    df = pd.DataFrame(data=data, columns=['Date','Artist','Track','Start'])
    df


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

    Код для любого количества артистов и песен у них ну и количество дней тоже сколько надо задашь. NUMBER_OF_DAYS. Поменяй да и все.

    ДОПОЛНЕНИЕ К ОТВЕТУ
    Как и обещал, подработал я свое решение, так как оно должно быть, меньше кода, быстрее и больше функциональности.

    from itertools import chain
    import pandas as pd
    import numpy as np
    
    
    songs = {
        'ANNA ASTI': ['Девочка танцуй','Грустный дэнс','Гармония'],
        'Три дня дождя': ['Демоны','Где ты','Перезаряжай'],
        'MACAN': ['Кино','Пополам','Бенз'],
    }
    
    NUMBER_OF_DAYS = 3
    NUMBER_OF_SONGS_PER_DAY = sum(len(value) for value in (songs.values()))
    STARTING_DATE = '2023-01-01'
    
    dates = pd.date_range(STARTING_DATE, periods=NUMBER_OF_DAYS, freq='1D')
    artists = list(chain(*[[key] * len(value) for key, value in songs.items()]))
    songs_per_day = list(chain(*songs.values()))
    
    index = pd.MultiIndex.from_product([dates,artists],names=['Date','Artist'])
    
    df = pd.DataFrame({
        'Songs':songs_per_day * NUMBER_OF_DAYS,
        'Start':np.random.randint(3000,1000000,NUMBER_OF_DAYS * NUMBER_OF_SONGS_PER_DAY),
        
    }, index=index).reset_index()
    
    df


    Вот это хороший читабельный pandas код, теперь я спокоен, а то вопрос то решил, но просто в лоб, а не так как следует.

    кстати обрати внимание, если запустишь код без reset_index(), у тебя будет многоуровневый индекс, посмотри как обращаться к любому из уровней индекса в документации. Ну и посмотри все созданные мною списки, что бы посмотреть идею, как я декомпозировал задачу. Потому что задачу ты задал хорошую, по сути дела словарь это неполная запись за день, из которой нужно формировать данные.
    Ответ написан
    2 комментария
  • Как удалить похожие строки из таблицы в Pandas, Python?

    Maksim_64
    @Maksim_64
    Data Analyst
    Ну смотрите первое мы имеем str акссесор который позволяет нам осуществить для каждой ячейки как будто она строка в python. Там огромное количество методов и можно даже сложный regex написать если нужно, и на основании его оставить только нужные строки. Второе у pandas есть метод drop_duplicates(), он удаляет все не уникальные строки для одной колонки или даже для комбинации. По желанию можно задать ему параметры и оставить только первое пявление из неуникальных значений или последнее.

    Способов для решение вашей задачи на самом деле много. Ну вот парочку на основании той информации что
    вами представлена. То есть для представленного вами примера они сработают. Если же это не сработает для всех строк я то не знаю их всех и ориентируюсь на то что представленно вами, то суть, как решать на изменится просто возможно нужно будет добавить какое то условие или какой нибудь regex. Но суть решения не изменится.

    df = pd.DataFrame({
        'urls':['123.ru','lalala.ru','lalala.ru/qwe','lalala.ru/12rwse','bebe.ru'],
        'other data':[1,1,1,1,1]
    })
    # Первый способ 
    new_df = df.loc[df['urls'].str.split('/').str[0].drop_duplicates().index]
    print(new_df)
    # Второй способ
    new_df = df[~df['urls'].str.contains('/')].drop_duplicates()
    print(new_df)


    Первый способ более общий мы разделяем по слешу берем первый элемент (домен), и избавляемся от всех повторяющихся строк. (Более надежно)

    Второй способ совсем слабая проверка мы выбираем те строки которые не содержат слеша, предполагая что первый раз (домен) встречается без слеша. (НЕ надежно)

    Если же оба примера не покрывают всех случаев (ЧТО скорее всего) то по этому же принципу нужно писать более сложное условие, и все.

    Ну вот автор уже и вопрос подредактировал что делает второй способ решения не рабочим да и первый надо менять тоже.
    df = pd.DataFrame({
        'urls':['http://123.ru/','http://lalala.ru','http://lalala.ru/qwe',
                'http://lalala.ru/12rwse','http://bebe.ru'],
        'other data':[1,1,1,1,1]
    })
    new_df = df.loc[df['urls'].str.split('//').str[1].str.split('/').str[0].drop_duplicates().index]
    print(new_df)
    Ответ написан
    Комментировать
  • Как добавить словарь в существующий датафрейм pandas?

    Maksim_64
    @Maksim_64
    Data Analyst
    Ну во первых append метод запрещен и будет удален, так что его не используем. Если в двух словах то преобразовать во фрейм и конкатенировать, ну а если не в двух то вот.
    Сначала разберем как добавить новую строку. Используем метод concat для этого. Откроете документацию посмотрите все довольно просто. В вашим случае немножечко сложнее потому что ваш словарь простой
    {key1: value, key2:value}, что бы создать фрейм из словаря он должен быть такого вида some_dict = {'key1':[value],'key2':[value]}. Тогда мы можем просто создать фрейм командой pd.DataFrame(some_dict). Ничего особо переделывать не придется, просто использовать дополнительный метод from_records.
    shapka = {'Кадастровый № ОКС':[],'Вид ОКС':[],'Назначение':[],'Адрес ОКС':[],'Площадь':[],'Вид права':[],'ФИО':[],'Номер рег. записи':[]}
    df = pd.DataFrame(shapka)
    
    slovar = {'Кадастровый № ОКС': 'тут текст', 'Вид ОКС': 'тут текст', 'Назначение': 'тут текст', 'Адрес ОКС': 'тут текст', 'Площадь': 'тут текст', 'Вид права': 'тут текст', 'ФИО': 'тут текст', 'Номер рег. записи': 'тут текст'}
    new_df = pd.concat([df, pd.DataFrame.from_records([slovar])] ,ignore_index=True)


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

    И еще на что хотел бы обратить внимание это метод from_records.
    d1 = {'A':1,'B':2}
    d2 = {'A':3,'B':4}
    df = pd.DataFrame.from_records([d1,d2])
    print(df)

    То есть нам доступен список словарей, для создания фрейма.
    Ответ написан
    Комментировать
  • Почему pandas выдает ошибку?

    Maksim_64
    @Maksim_64
    Data Analyst
    metrics_df[[
        "same_intervals_between_requests"

    пропущена запятая, посмотрите внимательнее. Если же причина не в этом (ошибка то очевидна), может ваше исключение до этого выскакивает, то опубликуйте задачу (что вы хотите сделать.). Возьмите маленький фрейм и во что он должен превратится. По тому что как можно поправлять код? Без задачи (что вы хотите что бы этот код делал).

    Потом вот здесь тоже ошибка
    df[["time_local", "id_session"]].groupby("id_session").apply(count_metric_using_shift)

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

    Вот я на маленьком фрейме сконструировал такую же ошибку, как у вас
    вот так будет ошибка потому что колонок где запускать функцию нет
    df = pd.DataFrame({
        'Cat':['A','A','B','A','B'],
        'Num1':[1,2,3,4,5],
        'Num2':[6,7,8,9,10]
    })
    df[['A','B']] = df[['Cat']].groupby('Cat').apply('mean')

    да ее можно убрать просто оставив df[['A','B']] =df.groupby('Cat').apply('mean') Но естествеено смысла в этом нет. Оно nan вернет. Нужно все переписывать, по этому и спрашиваю, какая задача.
    Ответ написан
  • Как разбить временной столбец на интервалы?

    Maksim_64
    @Maksim_64
    Data Analyst
    Смотрите если уж хочется разбивать на интервалы и создавать столбец с категориями то есть несколько стратегий но в целом для этого используется функция pd.cut, вот для вашей задачи я написал код.
    df= pd.DataFrame({'time':pd.date_range('2023-03-22', periods=48, freq='H')})
    bins = [0,5,11,16,22,24]
    labels = ['Ночь', 'Утро','День','Вечер','Ночь']
    df['session'] = pd.cut(df['time'].dt.hour, bins=bins, labels=labels, include_lowest=True,ordered=False)
    df

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

    Имейте ввиду да для определенных задач это имеет смысл, создавать категориальную переменную для интервала времени, но для многих случаев объекты работающие с временем и датой достаточны умны и вы можете осуществлять группы для временной последовательности это не обязательно GroupBy есть специальный метод resample. Для выборки вы можете установить вашу временную последовательность в индекс и затем использовать удобный метод between_time, и многие, многие другие. И в целом временная последовательность имеет dt атрибут и затем можно к ней обращаться day, hour, year и.т.д.
    Ответ написан
    1 комментарий
  • Почему pandas выдает предупреждение?

    Maksim_64
    @Maksim_64
    Data Analyst
    Довольно известное сообщение о предупреждении. На самом деле сейчас ведется разработка и в будущих версиях pandas это поведение должно принять более последовательный характер, потому что на данный момент оно непоследовательно. Что бы не повторять материал из свежей pydata. Вот ссылка Видео на видео где один из текущих разработчиков pandas объясняет все в деталях с примерами где будет это предупреждение а где нет почему оно возникает что с этим делать сейчас и что будет дальше.

    Если же в двух словах (Что плохо для данного вопроса, он глубже чем кажется), то предупреждение предупреждает о том что в вашем во фрейме из которого получен подсет данных могут произойти изменения при изменении значения в подсете.

    Но тема более глубокая и там есть код где это произойдет и где нет. Так что рекомендую видео.
    Ответ написан
    Комментировать
  • Как заменить pandas.append на pandas.concat?

    Maksim_64
    @Maksim_64
    Data Analyst
    Сначала собираете все датафреймы в отдельный лист, затем конкатенируете и все. По вашему коду должно быть как то так. Протестировать то код я не могу возможно где то опечатки. Собираете фреймы в лист в цикле, а затем за пределами цикла конкатенируете в общий фрейм и вне цикла записываете в файл.
    import io
    import pandas as pd
    
    
    excel_file = io.BytesIO()
    excel_file.name = "table_excel.xlsx"
    all_frames = []
    for history in ads:
        item_title = history.get("item_title")
        item_price = history.get("item_price")
        current_df = pd.DataFrame(
            {
                "Имя": [item_title],
                "Цена": [item_price],
            }
        )
        all_frames.append(currend_df)
    final_df = pd.concat(all_frames, ignore_index=True)
    
    final_df.to_excel(excel_file, encoding="utf-8", index=False)
    Ответ написан