Make a attendace student report using pandas

Viewed 270

I have some csv table from google form for attendance report. The data looks like this

df1= pd.read_csv("12-9-2020.csv")
df1

Name            StudentID
Robert C        102
Jessica Myla    103
Nana D          105

df2= pd.read_csv("12-10-2020.csv")
df2

Name            StudentID
J Myla          103
Harris Kurt     104
Nana Duncan     105

I have many tables that I want to make a compilation attendance report. The basic compilation attendance report looks like this:

df_Basic
Name             StudentID  12/9/2020   12/10/2020
Robert Case      102        0           0
Jessica Myla     103        0           0
Harris Kurt      104        0           0
Nana Duncan      105        0           0

I want to input the data form df1, df2 to the compilation attendance report. If the student attend the class, it must be as 1 and the spell of the student name will match with the compilation attendance report format.

The desired result looks like this:

df_Result
Name          StudentID 12/9/2020   12/10/2020
Robert Case   102       1           0
Jessica Myla  103       1           1
Harris Kurt   104       0           1
Nana Duncan   105       1           1

Thank you for helping me

3 Answers

Here is a solution for two dataframes:

df1.set_index('StudentID', inplace=True)
df1.loc[:, '12-9-2020.csv'] = 1

df2.set_index('StudentID', inplace=True)
df2.loc[:, '12-10-2020.csv'] = 1
df1 = df1.join(df2, how='outer', rsuffix='_')
df1['Name'] = df1['Name'].combine_first(df1['Name_'])
df1.drop('Name_', axis=1, inplace=True)

df1.fillna(0).reset_index()

For more dataframes, repeat the lines 3-7, as needed.

Here is a full solution:

  1. df - dynamically read in all files into one dataframe from a specific folder on your desktop (and create Date column with assign and derive date from the filename). YOU must specify this in the files variable
  2. df_attendance - with .groupby, return 1 or 0 by StudentID and put Date on columns
  3. df_names - Normalize Name data by choosing the longest name per ID as the Name
  4. df_attendance - join the two dataframes df_attendance and df_names

import glob
files = glob.glob(r'Desktop\Students\*.csv')
df = pd.concat([pd.read_csv(f).assign(Date=pd.to_datetime(os.path.basename(f)[:-4]))
                for f in files])
df_attendance = (df.groupby(['StudentID', df['Date'].dt.date]).size()
                   .unstack(1).fillna(0).astype(int))
df_names = (df.groupby(['StudentID'])['Name'].apply(list)
              .apply(lambda x: [y for y in x if len(y) == 
                                max([len(z) for z in x])][0])).to_frame() # this reads.. per student choose the name that is the longest name
df_Result = df_names.join(df_attendance).reset_index()
df_Result
Out[1]: 
   StudentID          Name  2020-12-09  2020-12-10
0        102      Robert C           1           0
1        103  Jessica Myla           1           1
2        104   Harris Kurt           0           1
3        105   Nana Duncan           1           1


If you want to change the formats of the dates in the date column, then you can run the below code, which is very similar:

files = glob.glob(r'Desktop\Students\*.csv')
df = pd.concat([pd.read_csv(f).assign(Date=pd.to_datetime(os.path.basename(f)[:-4]))
                for f in files]).sort_values(['StudentID', 'Date'])
df_attendance = (df.groupby(['StudentID', df['Date'].dt.strftime('%m/%d/%y')], sort=False).size()
                   .unstack(1).fillna(0).astype(int))
df_names = (df.groupby(['StudentID'])['Name'].apply(list)
              .apply(lambda x: [y for y in x if len(y) == 
                                max([len(z) for z in x])][0])).to_frame()
df_Result = df_names.join(df_attendance).reset_index()
df_Result

Out[2]: 
   StudentID          Name  12/09/20  12/10/20
0        102      Robert C         1         0
1        103  Jessica Myla         1         1
2        104   Harris Kurt         0         1
3        105   Nana Duncan         1         1

Per your comment, you can do something like this. Please note it is BETTER to use StudentID instead of Name for a direct match, so just replace "StudentID" with "Name" if you use that:

df_list = pd.read_csv(file) # pass the filepath of you file and must have column "Name:
df_list = df_list[~(df_list['Name'].isin(df_Result['Name']))] #find students not in the file
df_Result = pd.concat([df_Result, df_list[['Name']]]).fillna(0)
df_Result

You can Probably do it with

df1= pd.read_csv("12-9-2020.csv")
df1

Name            StudentID
Robert C        102
Jessica Myla    103
Nana D          105

df2= pd.read_csv("12-10-2020.csv")
# get ids from second table
ids_of_presenties = df2['StudentID'].values.tolist()

# in first dataframe create a date column
current_date = '12/9/2020'
df1[current_date] = 0
df1[df1['StudentID'].isin(ids_of_presenties)][current_date] = 1 # mark the attendance of the only student present.

Don't have your dataframe. hope it's good

Related