Получение метки времени из одного столбца и вставка ее в другой с пандами

#python #python-3.x #pandas #dataframe #python-requests

Вопрос:

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

        full_path             name             created           modified
0    C:T11.txt            1.txt            14:04:30             NaN
1    C:T11.txt            1.txt              NaN              14:04:30
2    C:T1T21.txt         1.txt            14:10:30              NaN
3    C:T1T21.txt         1.txt              NaN              14:10:30
4    C:T1T2T31.txt      1.txt            14:15:30             NaN
5    C:T1T2T31.txt      1.txt              NaN              14:15:30
6    C:T1T2T3T41.txt   1.txt            14:20:30             NaN
7    C:T1T2T3T41.txt   1.txt              NaN              14:20:30
8    C:T12.txt            2.txt            14:25:30             NaN
9    C:T12.txt            2.txt              NaN              14:25:30
10   C:T1T22.txt         2.txt            14:30:30             NaN
11   C:T1T22.txt         2.txt              NaN              14:30:30
12   C:T1T2T32.txt      2.txt            14:35:30             NaN
13   C:T1T2T32.txt      2.txt              NaN              14:35:30
14   C:T1T2T3T42.txt   2.txt              NaN              14:40:30
 

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

 m0 = (df["full_path"].ne(df["full_path"].shift(1, fill_value=df["full_path"].iloc[0])) amp; df["name"].eq(df["name"].shift(fill_value=df["name"].iloc[0])))
m1 = df["full_path"].eq(df.loc[df["full_path"].str.rsplit("\", 2).str[-2] == 'T1', 'full_path'])
m2 = df["full_path"].eq(df.loc[df["full_path"].str.rsplit("\", 2).str[-2] == 'T2', 'full_path'])
m3 = df["full_path"].eq(df.loc[df["full_path"].str.rsplit("\", 2).str[-2] == 'T3', 'full_path'])
m4 = df["full_path"].eq(df.loc[df["full_path"].str.rsplit("\", 2).str[-2] == 'T4', 'full_path'])

df['T1'] = np.where(m0 amp; m1, df['created'], "")
df['T2'] = np.where(m0 amp; m2, df['created'], "")
df['T3'] = np.where(m0 amp; m3, df['created'], "")
df['T4'] = np.where(m0 amp; m4, df['created'], "")

df = df.groupby(['name'], sort=False).agg({'full_path':'last','created':'first', 'modified':'last','T1':'first', 'T2':lambda x: ' '.join(set(x)), 'T3':lambda x: ' '.join(set(x)), 'T4':'last'}).reset_index()
 

И это дает мне фрейм данных, подобный этому:

    full_path             name   created    modified      T1       T2        T3          T4
0  C:T1T2T3T41.txt  1.txt  14:04:30   14:20:30  14:04:30   14:10:30  14:15:30   14:20:30  
1  C:T1T2T3T42.txt  2.txt  14:25:30   14:40:30  14:25:30   14:30:30  14:35:30      NaN
 

Как я могу изменить свой код, чтобы определить, например, для файла 2.txt когда он переместился в папку T4, если столбец «создан» в NaN, получите метку времени из столбца «изменен» и создайте фрейм данных, подобный этому:

    full_path             name   created    modified      T1       T2        T3          T4
0  C:T1T2T3T41.txt  1.txt  14:04:30   14:20:30  14:04:30   14:10:30  14:15:30   14:20:30  
1  C:T1T2T3T42.txt  2.txt  14:25:30   14:40:30  14:25:30   14:30:30  14:35:30   14:40:30
 

Ответ №1:

Итак, чтобы ответить на конкретный вопрос. Используйте fillna и передайте значения из «изменено» перед тем groupby , как они заполнят значения NaN в T4 значениями из изменено:

 df['T4'] = df['T4'].fillna(df['modified'])
 

В качестве альтернативы, возможно, используйте что-то вроде pathlib, чтобы получить имя родительской папки.

Импорт

 from pathlib import PurePath

import numpy as np
import pandas as pd
 

Образец Кадра

 df = pd.DataFrame({
    'full_path': {0: 'C:\T1\1.txt', 1: 'C:\T1\1.txt',
                  2: 'C:\T1\T2\1.txt', 3: 'C:\T1\T2\1.txt',
                  4: 'C:\T1\T2\T3\1.txt',
                  5: 'C:\T1\T2\T3\1.txt',
                  6: 'C:\T1\T2\T3\T4\1.txt',
                  7: 'C:\T1\T2\T3\T4\1.txt',
                  8: 'C:\T1\2.txt', 9: 'C:\T1\2.txt',
                  10: 'C:\T1\T2\2.txt',
                  11: 'C:\T1\T2\2.txt',
                  12: 'C:\T1\T2\T3\2.txt',
                  13: 'C:\T1\T2\T3\2.txt',
                  14: 'C:\T1\T2\T3\T4\2.txt'},
    'name': {0: '1.txt', 1: '1.txt', 2: '1.txt', 3: '1.txt',
             4: '1.txt', 5: '1.txt', 6: '1.txt', 7: '1.txt',
             8: '2.txt', 9: '2.txt', 10: '2.txt', 11: '2.txt',
             12: '2.txt', 13: '2.txt', 14: '2.txt'},
    'created': {0: '14:04:30', 1: np.nan, 2: '14:10:30', 3: np.nan,
                4: '14:15:30', 5: np.nan, 6: '14:20:30', 7: np.nan,
                8: '14:25:30', 9: np.nan, 10: '14:30:30', 11: np.nan,
                12: '14:35:30', 13: np.nan, 14: np.nan},
    'modified': {0: np.nan, 1: '14:04:30', 2: np.nan, 3: '14:10:30',
                 4: np.nan, 5: '14:15:30', 6: np.nan, 7: '14:20:30',
                 8: np.nan, 9: '14:25:30', 10: np.nan, 11: '14:30:30',
                 12: np.nan, 13: '14:35:30', 14: '14:40:30'}
})
 

Получить Имена Папок

 # Get Parent Folder Name From Each Path
df['folder'] = df['full_path'].apply(lambda x: PurePath(x).parent.name)
print(df.to_string())
 
                full_path   name   created  modified folder
0            C:T11.txt  1.txt  14:04:30       NaN     T1
1            C:T11.txt  1.txt       NaN  14:04:30     T1
2         C:T1T21.txt  1.txt  14:10:30       NaN     T2
3         C:T1T21.txt  1.txt       NaN  14:10:30     T2
4      C:T1T2T31.txt  1.txt  14:15:30       NaN     T3
5      C:T1T2T31.txt  1.txt       NaN  14:15:30     T3
6   C:T1T2T3T41.txt  1.txt  14:20:30       NaN     T4
7   C:T1T2T3T41.txt  1.txt       NaN  14:20:30     T4
8            C:T12.txt  2.txt  14:25:30       NaN     T1
9            C:T12.txt  2.txt       NaN  14:25:30     T1
10        C:T1T22.txt  2.txt  14:30:30       NaN     T2
11        C:T1T22.txt  2.txt       NaN  14:30:30     T2
12     C:T1T2T32.txt  2.txt  14:35:30       NaN     T3
13     C:T1T2T32.txt  2.txt       NaN  14:35:30     T3
14  C:T1T2T3T42.txt  2.txt       NaN  14:40:30     T4
 

Тогда конечный результат может быть легче достигнут:

 # Get Parent Folder Name From Each Path
df['folder'] = df['full_path'].apply(lambda x: PurePath(x).parent.name)
# Keep Groupby Name handy for later
g = df.groupby('name')
# Transform each group to be the last path
df['full_path'] = g['full_path'].transform('last')
# combine_first created with modified (new column to not affect data)
df['c_m'] = df['created'].combine_first(df['modified'])

index_cols = ['full_path', 'name']
# Pivot to wide format
df = df.pivot_table(index=index_cols,
                    columns='folder',
                    values='c_m',
                    aggfunc='first')

# Add Summary Columns
summary_cols = ['created', 'modified']
# Merge on name
df = df.reset_index() 
    .merge(g[summary_cols].agg({'created': 'first', 'modified': 'last'}),
           on='name')

# Re-order Columns and axis names
df = df[[*index_cols,
         *summary_cols,
         *df.columns.difference(summary_cols   index_cols)]] 
    .rename_axis(None, axis=1)

# Output
print(df.to_string(index=False))
 

df :

            full_path  name  created modified       T1       T2       T3       T4
C:T1T2T3T41.txt 1.txt 14:04:30 14:20:30 14:04:30 14:10:30 14:15:30 14:20:30
C:T1T2T3T42.txt 2.txt 14:25:30 14:40:30 14:25:30 14:30:30 14:35:30 14:40:30
 

Комментарии:

1. Большое спасибо @henryecker за ответ. Кроме того, ваша альтернатива намного лучше. Я собираюсь использовать его вместо своего.

2. Эй, @henryecker, мой реальный фрейм данных намного больше, на нем разные имена файлов. С вашим решением, когда я делаю df.pivot_table (), файлы сортируются в алфавитном порядке, а затем, когда мы говорим df[summary_cols] = g[summary_cols .agg ({«создан»: «первый», «изменен»: «последний»}). to_numpy(). Он смешивает «созданные» и «измененные» метки времени с другими файлами. Можем ли мы сделать сводную таблицу, не сортируя ее по алфавиту?

3. Я обновил ответ. Я думаю, что объединение name , вероятно, является лучшим подходом, чем попытка сопоставить сортировку. Дай мне знать, если это сработает.

4. Эй, @henryecker, да, теперь он работает отлично. Еще раз спасибо!

5. Эй,@henryecker, если, например, файл 1.txt после того, как некоторое время будет перенесено обратно в T3, есть ли возможный способ удалить отметку времени в T4?