我使用的是panda,我有一列考勤时间戳数据(Date(。我想将当天的值拆分为(InTime(和(OutTime(列。
df = df[['Date']]
Date
Thu 1/09 9:10 AM
Thu 1/09 6:10 PM
Fri 2/09 9:04 AM
Fri 2/09 6:02 PM
我正在努力达到以下结果。
In Time OutTime
Thu 1/09 9:10 AM Thu 1/09 6:10 PM
Fri 2/09 9:04 AM Fri 2/09 6:02 PM
谢谢。
编辑
谢谢你的帮助。问题是数据没有达到应有的整洁程度。缺少In-Time/Out-Time或接近重复的记录。+我是一个基本的python用户,我甚至无法理解根据我的需求修改它的代码。
我请求查看完整的场景,以及我迄今为止为实现预期结果所做的尝试。
这是一个考勤机数据,用户要么忘记标记考勤,要么机器创建了一个重复条目以获得更长的拇指印象。因此,所提供的代码将AM和PM列混淆在一起,只要它发现任何重复或丢失的记录。
样本数据看起来像这个
User Date
11 Thu 1/09 9:10 AM
3 Thu 1/09 9:10 AM
4 Thu 1/09 9:10 AM
2 Thu 1/09 9:23 AM
5 Thu 1/09 9:39 AM
... ... ...
12 Fri 30/09 5:55 PM
5 Fri 30/09 6:01 PM
6 Fri 30/09 6:04 PM
11 Fri 30/09 6:09 PM
我正在尝试为每个用户创建多个.csv
文件,其中"输入"one_answers"输出"时间戳位于单独的列中,包括非连续天的空记录,以便将其粘贴到已创建的Excel模板中。
df = pd.read_csv('input.csv', encoding="utf-8", sep=',')
df = df[["User", "Date"]]
dataframe = pd.DataFrame(df,
columns=['User', 'Date'])
users = {
'falcon': 2,
'charlie': 3,
}
for username, ID in users.items():
df = dataframe.loc[dataframe['User'] == ID]
df = df[['Date']]
df.to_csv(username + ".csv", encoding="utf-8", sep=',', header=False, index=False)
结果
Thu 1/09 9:10 AM
Thu 1/09 6:11 PM
Fri 2/09 9:18 AM //Missing PM
Sat 3/09 10:44 AM
Sat 3/09 6:00 PM
Mon 5/09 9:22 AM //Missing PM
Tue 6/09 9:09 AM
Tue 6/09 6:25 PM
Wed 7/09 9:18 AM
Wed 7/09 6:33 PM
我试图将这些日期分开,这样带有AM/PM的条目就可以在其相应的列中分开(包括缺少日期的空记录(。
以下是一个包含pandas.DataFrame.join
和pandas.DataFrame.shift
的解决方案:
new_df = (
df.add_suffix('_In_time')
.join(df.shift(-1).add_suffix('_Out_time'))
.iloc[::2]
)
#输出:
print(new_df)
Date_In_time Date_Out_time
0 Thu 1/09 9:10 AM Thu 1/09 6:10 PM
1 Fri 2/09 9:04 AM Fri 2/09 6:02 AM
代码
注意:这段代码是在考虑原始帖子的情况下编写的(请参阅下面的更新部分(
import pandas as pd
from io import StringIO
from dateutil.parser import parse
data = '''User,Date
1,Thu 1/09 9:10 AM
1,Thu 1/09 6:11 PM
1,Fri 2/09 9:18 AM
1,Sat 3/09 10:44 AM
1,Sat 3/09 6:00 PM
1,Mon 5/09 9:22 AM
1,Tue 6/09 9:09 AM
1,Tue 6/09 6:25 PM
1,Wed 7/09 9:18 AM
1,Wed 7/09 6:33 PM
2,Thu 1/09 9:13 AM
2,Thu 1/09 6:10 PM
2,Fri 2/09 9:10 AM
2,Fri 2/09 6:10 PM
2,Sat 3/09 10:40 AM
2,Sat 3/09 5:55 PM
2,Tue 6/09 6:21 PM
2,Wed 7/09 9:10 AM
2,Wed 7/09 6:30 PM
'''
df = pd.read_csv(
StringIO(data),
parse_dates=[1],
date_parser=lambda x: parse(x, dayfirst=True)
)
df['Day'] = df['Date'].dt.date
df['InOut'] = df['Date'].dt.strftime('%p').map({'AM':'In time', 'PM':'Out time'})
output = df.pivot(index=['User','Day'], columns='InOut',values='Date')
users = df['User'].unique()
days = pd.date_range(start=df['Day'].min(), end=df['Day'].max(), freq='D')
index = pd.MultiIndex.from_product([users, days])
output = output.reindex(index, fill_value=pd.NA)
for user_id, group in output.groupby(level=0):
group.to_csv(
f'user_{user_id}.csv',
index=False,
date_format='%a %d/%m %I:%M %p'
)
备注
假设我们有一些csv格式的数据:
用户日期查看您共享的csv,很明显日期格式存在问题(不一致,但目前不是问题(和重复条目。
请注意,有些行缺少AM时间,有些行则缺少PM时间。假设一个用户早上进,下午出,我做了一个简单的循环,检查每个用户的进和出时间,并加上";缺少";以防条目丢失。为每个用户生成一个数据帧,然后连接所有数据帧。如果需要,可以对最终的数据帧进行排序,但必须首先对数据格式进行标准化。我没有做这一步,因为这不是问题的一部分,没有它问题可以解决
import pandas as pd
input_csv = '/Users/alec/Downloads/python-split-dates-data/sandbox.csv'
df = pd.read_csv(input_csv)
print(df)
User Date
0 11 Sun 9/01 9:10 AM
1 3 Sun 9/01 9:10 AM
2 4 Sun 9/01 9:10 AM
3 2 Sun 9/01 9:23 AM
4 5 Sun 9/01 9:39 AM
.. ... ...
339 12 9/30/22 5:55 PM
340 5 9/30/22 6:01 PM
341 6 9/30/22 6:04 PM
342 11 9/30/22 6:09 PM
343 4 9/30/22 6:19 PM
[344 rows x 2 columns]
cleaned_df = []
for user, group in df.drop_duplicates().groupby('User'):
am = [] #store AM entries
pm = [] #store PM entries
for i, row in group.iterrows():
if row.Date.endswith('AM'):
am.append(row.Date)
elif row.Date.endswith('PM'):
while len(am) <= len(pm):
am.append('missing IN') #add missing
while len(pm) < len(am)-1:
pm.append('missing OUT') #add missing
pm.append(row.Date)
assert len(am) == len(pm) #double check data is consistent
_df = pd.DataFrame({'User':[user]*len(am), 'IN':am, 'OUT':pm})
cleaned_df.append(_df)
new_df = pd.concat(cleaned_df)
print(new_df)
User IN OUT
0 2 Sun 9/01 9:23 AM Sun 9/01 5:55 PM
1 2 Wed 9/02 9:20 AM Wed 9/02 5:46 PM
2 2 Wed 9/03 9:24 AM Wed 9/03 5:46 PM
3 2 Mon 9/05 9:23 AM Mon 9/05 5:40 PM
4 2 Thu 9/06 9:26 AM Thu 9/06 5:49 PM
.. ... ... ...
0 12 missing IN 9/23/22 5:54 PM
1 12 9/27/22 10:24 AM 9/27/22 1:34 PM
2 12 9/28/22 9:01 AM 9/28/22 5:51 PM
3 12 9/29/22 9:08 AM 9/29/22 5:52 PM
4 12 9/30/22 9:16 AM 9/30/22 5:55 PM
[182 rows x 3 columns]
另一种方法,将列转换为datetime并使用它。尝试:
df
Date
0 Thu 1/09 9:10 AM
1 Thu 1/09 6:10 PM
2 Fri 2/09 9:04 AM
3 Fri 2/09 6:02 PM
df['Date'] = pd.to_datetime(df['Date'] + ' 2022', format='%a %d/%m %H:%M %p %Y')
df['day'] = df['Date'].dt.date
df['time'] = df['Date'].dt.time
df.groupby('day').agg(InTime=('time', 'first'), OutTime=('time', 'last')).reset_index()
day InTime OutTime
0 2022-09-01 09:10:00 06:10:00
1 2022-09-02 09:04:00 06:02:00
基于pandas.DataFrame.pivot
:的可能解决方案
# separate day from time
df[['Date1', 'Date2']] = df['Date'].str.split('(?<=d)s(?=d)', expand=True)
# create column with colnames for the new columns to be created by pivot
df['names'] = ['inTime', 'OutTime'] * (len(df)//2)
(df.pivot(index='Date1', columns='names', values='Date')
.reset_index(drop=True).iloc[:,::-1])
输出:
names inTime OutTime
0 Fri 2/09 9:04 AM Fri 2/09 6:02 PM
1 Thu 1/09 9:10 AM Thu 1/09 6:10 PM
如果数据集没有从早到晚的时间排序,则解决方案可能如下:
# separate day from time
df[['Date1', 'Date2', 'Date3']] = df['Date'].str.split(
'(?<=d)s(?=d)|s(?=.M$)', expand=True)
# this is needed if the times are no sorted in the initial dataset
df = df.sort_values(['Date1', 'Date3', 'Date2'])
# create column with colnames for the new columns to be created by pivot
df['names'] = ['inTime', 'OutTime'] * (len(df)//2)
(df.pivot(index='Date1', columns='names', values='Date')
.reset_index(drop=True).iloc[:,::-1])
完整代码:
import pandas as pd
import numpy as np
from io import StringIO
text = """
Date
Thu 1/09 9:10 AM
Thu 1/09 6:10 PM
Fri 2/09 9:04 AM
Fri 2/09 6:02 PM
"""
df = pd.read_csv(StringIO(text), sep='s{2,}', engine='python')
# separate day from time
df[['Date1', 'Date2']] = df['Date'].str.split('(?<=d)s(?=d)', expand=True)
# create column with colnames for the new columns to be created by pivot
df['names'] = ['inTime', 'OutTime'] * (len(df)//2)
df = (df.pivot(index='Date1', columns='names', values='Date')
.reset_index(drop=True).iloc[:,::-1])
print(df)