#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?