Добавление ведущих нулей в столбцы данных при загрузке из файлов CSV с помощью pandas

У меня есть сценарий для загрузки и объединения данных временных рядов из двух файлов .csv, имеющих одинаковое базовое имя файла (указанное как путь с помощью Pathlib), но разные суффиксы. Учитывая, что импорт данных из файлов .csv работает правильно, я привожу сюда минимальный рабочий пример с данными, предоставленными с использованием StringIO:

import pandas as pd
from io import StringIO

def load_data():
    headers_0 = ['a', 'b', 'c']  # Headers for first file. May have more entries than columns in file
    headers_1 = ['d', 'e']       # Headers for second file.

    data_0 = pd.read_csv(
        StringIO(
          """
            0 1 2
            3 4 5
            6 7 8
          """
          )
        , header=None, delim_whitespace=True)
    data_0.columns = headers_0[0:data_0.shape[1]]

    data_1 = pd.read_csv(
        StringIO(
          """
            A B
            C D
          """
          )
        , header=None, delim_whitespace=True)
    data_1.columns = headers_1[0:data_1.shape[1]]

    data = data_0.join(data_1)
    data.fillna(0, inplace=True)

    print(data)

До сих пор я использовал load_data только для наборов данных, где data_0 и data_1 имеют одинаковую длину столбцов (одинаковую длину временного ряда). Однако сейчас я сталкиваюсь с ситуацией, когда длина столбца data_1 короче, чем data_0; это потому, что данные в data_1 начинают записываться позже, чем в data_0.

Как использовать pandas для заполнения столбцов data_1 ведущими нулями так, чтобы длина столбца как в data_0, так и в data_1 была одинаковой? Я считаю, что строка data.fillna(0, inplace=True) заполняет несоответствие длины конечными нулями; есть ли очевидный способ изменить это на ведущие нули? Обратите внимание, что я априори не знаю длину ни одного набора данных, поэтому я был бы признателен за помощь в поиске решения, которое работает на основе длины данных, загруженных с помощью pandas. Выполнение приведенного выше примера дает результат

   a  b  c  d  e
0  0  1  2  A  B
1  3  4  5  C  D
2  6  7  8  0  0

что, очевидно, не является желаемым эффектом (нули в столбцах d и e будут в строке 0, а не в строке 2).

Я пробовал разные варианты DataFrame.fillna, например method=backfill, но ни одна из этих попыток не дала ожидаемого результата.

О, вы не знаете о слиянии? См. Слияние панд 101

wjandrea 27.06.2024 00:32

На самом деле это не минимальный рабочий пример, поскольку в нем отсутствуют данные примера (входные данные, желаемый результат и фактический результат). Вы также должны показать, как вызывается функция. Или, если синтаксический анализ CSV работает отлично, просто укажите сами data_0 и data_1 (то есть примеры версий). См. Как сделать хорошие воспроизводимые примеры панд.

wjandrea 27.06.2024 00:46

Извиняюсь, @wjandrea, я добавлю необходимые данные, чтобы сделать их минимальным рабочим примером, когда в следующий раз получу доступ к своему компьютеру.

PhysyCola 27.06.2024 01:19
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
3
93
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вот один из подходов:

  • Поменяйте порядок строк вашего dfs с помощью [::-1] и примените df.reset_index с drop=True
  • Примените pd.concat к axis=1 и снова поменяйте местами + reset_index.
  • Наконец, примените df.fillna
import pandas as pd
from io import StringIO

def load_data(filename):
    
    headers_0 = ['a', 'b', 'c']
    headers_1 = ['d', 'e']

    # using StringIO for mre 
    # + `sep = "\s+"` for `delim_whitespace=True` (deprecated since 2.2.0)
    data_0 = pd.read_csv(StringIO(c_0), header=None, sep = "\s+")
    data_0.columns = headers_0[0:data_0.shape[1]]

    data_1 = pd.read_csv(StringIO(c_1), header=None, sep = "\s+")
    data_1.columns = headers_1[0:data_1.shape[1]]

    data = (
        pd.concat(
            [df[::-1].reset_index(drop=True) for df in [data_0, data_1]], 
            axis=1
        )[::-1]
        .reset_index(drop=True)
        .fillna(0)
    )

    return data
c_0 = """0 1 2
3 4 5
6 7 8"""

c_1 = """A B
C D
"""

load_data('c')

   a  b  c  d  e
0  0  1  2  0  0
1  3  4  5  A  B
2  6  7  8  C  D

Будет работать независимо от того, какой из них длиннее.


Другой вариант — использовать df.shift с fill_value:

def load_data2(filename):
    
    # `data_0` and `data_1` same as above

    diff = len(data_0) - len(data_1)
    
    data = pd.concat([data_0, data_1], axis=1)
    if diff > 0:
        data[data_1.columns] = data[data_1.columns].shift(diff, fill_value=0)
    elif diff < 0:
        data[data_0.columns] = data[data_0.columns].shift(abs(diff), fill_value=0)
    
    return data

Преимущество этой опции в том, что она заполняет только значения NaN в смещенной области. Например.:

c_0 = """0 1 2
3 4 5
6 7 8"""

c_1 = """A B
C 
"""

load_data2('c')

   a  b  c  d    e
0  0  1  2  0    0
1  3  4  5  A    B
2  6  7  8  C  NaN # with my `load_data` above, this `NaN` gets filled too!

Конечно, если вы все равно хотите, чтобы все значения NaN были заполнены, просто используйте fillna и здесь.

Спасибо за ответ @ouroboros1! Из вашего примера выполнения кода выходит, что это добавление нулей после данных c_1, а не перед ними? Я ожидаю, что нули в столбцах «d» и «e» появятся первыми?

PhysyCola 27.06.2024 01:21

Да, моя вина. Обновлено :)

ouroboros1 27.06.2024 01:22

Спасибо! Я отметил это как ответ, учитывая, что ваше первое решение является наиболее компактным и требует наименьшего количества if/then операторов.

PhysyCola 01.07.2024 06:21

Я не особо разбираюсь в пандах, мне удалось найти решение по-своему:

import pandas as pd
from pathlib import Path

def load_data(filename):
    headers_0 = ['a', 'b', 'c']
    headers_1 = ['d', 'e']

    data_0 = pd.read_csv(str(filename.with_suffix('')) + '_0.csv', header=None, delim_whitespace=True)
    data_0.columns = headers_0[0:data_0.shape[1]]

    data_1 = pd.read_csv(str(filename.with_suffix('')) + '_1.csv', header=None, delim_whitespace=True)
    data_1.columns = headers_1[0:data_1.shape[1]]

    len_0 = len(data_0)
    len_1 = len(data_1)

    if len_0 > len_1:
        zeros_to_prepend = pd.DataFrame(0, index=range(len_0 - len_1), columns=data_1.columns)
        data_1 = pd.concat([zeros_to_prepend, data_1], ignore_index=True)

    data = data_0.join(data_1)
    return data

filename = Path('filename/') # I didn't really understand what this was for, so just entered filename
data = load_data(filename)
print(data)

Это был мой результат:

    a   b   c    d    e
0   1   2   3    0    0
1   4   5   6    0    0
2   7   8   9  100  200
3  10  11  12  300  400

При использовании pandas у меня также было несколько предупреждений. В нем говорилось, что ключевое слово, используемое в пандах, устарело. Я использую Linux, поэтому с моей стороны могут возникнуть проблемы!

«Ключевое слово, используемое в пандах, устарело» — Какое? delim_whitespace фактически устарел; вы можете проверить документы.

wjandrea 27.06.2024 01:22

@wjandrea Ох, ок. Спасибо за информацию. Но подождите, они изменили это sep='\s+', если я правильно прочитал. Хотя это так излишне сложно без всякой причины.

Mathew Fedasenka 27.06.2024 01:43

Другие вопросы по теме