Pandas Dataframe генерирует переменные с использованием предыдущих строк - PullRequest
0 голосов
/ 05 августа 2020

Я пытаюсь создать больше переменных для своего набора данных. Мои данные хранятся в нескольких файлах, и, используя pandas, я могу прочитать только один файл за раз из-за ограничений памяти. Каждый файл csv содержит данные за один месяц и выглядит примерно так:


Index     Date          Sender     Recipient     Quantity     Type
------------------------------------------------------------------------
79XT     26-03-19       Adam       Tiffany       72           Box
57ZY     14-03-19       Josh       Ross          13           Snack
29UQ     19-03-19       Adam       Alex          60           Fruit
56PY     06-03-19       Lucy       Alex          29           Book
41BR     28-03-19       Josh       Steve         33           Snack

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

Index     Date          Sender     Recipient     Quantity     Type     Days Since          Days Since         Cumulative      Quantity Increase          First Shipment   
                                                                       Previous Shipment   First Shipment     Quantity        from Previous Shipment     to This Recipient?
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
79XT     26-03-19       Adam       Tiffany       72           Box      7                   62                 1792            12                         0
57ZY     14-03-19       Josh       Ross          13           Snack    NaN                 NaN                13              NaN                        1  
29UQ     19-03-19       Adam       Alex          60           Fruit    5                   55                 1730            -7                         1
56PY     06-03-19       Lucy       Alex          29           Book     23                  32                 88              -4                         0          
41BR     28-03-19       Josh       Steve         33           Snack    14                  14                 46              20                         1

Как видно из желаемого фрейма данных выше, новые переменные генерируются на основе предыдущих наблюдений отправителя. Какой способ создания таких характеристик является наименее затратным в вычислительном отношении? Мне нужно будет получить информацию из всех моих ежемесячных CSV-файлов, чтобы собрать такие данные. Существует более 200 000 уникальных отправителей, поэтому на чтение файлов csv и создание фрейма данных и файла csv для каждого уникального отправителя и объединения этих данных с ежемесячными файлами csv потребуются недели. Мне известно о распространении dask и dask, но я хочу узнать, есть ли для меня более простой способ реализовать то, что я пытаюсь сделать.

Ответы [ 2 ]

2 голосов
/ 05 августа 2020

Здесь у меня другой подход. Я бы попытался

  1. преобразовать все csv в parquet (в конце концов увидеть этот ответ ), изменив dtypes. Минимум
df['Date'] = df['Date'].astype("M8")

или

df['Date'] = pd.to_datetime(df['Date'])
Повторное разделение отправителем. Я предполагаю, что все файлы паркета находятся в папке processed.
import dask.dataframe as dd
df = dd.read_parquet('processed')
df.to_parquet('processed2', partition_on='Sender')

Теперь у вас много файлов в каждом Sender=username, вы должны объединить их все в один файл

Теперь вы можете создать свою функцию для каждого Sender=username

def fun(df):
    df = df.sort_values("Date")
    df["Day Since Prev Shipment"] = df["Date"].diff().dt.days
    df["Day Since First Shipment"](df["Date"] - df["Date"].min()).dt.days
    df["Cumulative Quantity"] = df["Quantity"].cumsum() 
    df["Quantity difference"] = df["Quantity"].diff()
    grp = df.groupby("Recipient")["Date"].min().reset_index(name="First Shipment")
    df = pd.merge(df, grp, how="left", on="Recipient")
    df["First Shipment"] = (df["Date"]==df["First Shipment"]).astype("int8")
    return df
2 голосов
/ 05 августа 2020

Я вижу несколько подзадач в вашей проблеме.

df = df.merge(df.groupby("sender").agg(first_occurence_date=("Date","min"))["sender", "first_occurrence_date"], on="sender", how="left")
# Computationally likely inefficient, and doesn't solve multiple file-issue immediately.
  • Вычислительно эффективные решения: для быстрого чтения рассмотрите возможность использования .feather в качестве эффективного формата хранения. Стандарт для этого изменения, поэтому всегда сохраняйте .csv в качестве резервной копии. Вы можете записать файл в виде пера, как это df.to_feather("filename")

Рассмотрите возможность факторизации ваших строк с помощью pd.factorize(), как описано в Pandas Docs: pd.Factorize () - Я не видел тестов по этому поводу, но сравнение int быстрее, чем string.

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

...