【问题标题】:Unable to calculate the frequency of unique values in a columns无法计算列中唯一值的频率
【发布时间】:2020-07-18 09:21:13
【问题描述】:

我正在做一个项目,需要我计算一个学生在场的次数和他在不同学科课程中缺席的次数,并计算他的出勤率。我有他的出勤记录如下

    Attend  Date    Subject
96  Present 09-04-2020  AM-II
69  Present 16-04-2020  AM-II
61  Present 20-04-2020  AM-II
49  Present 22-04-2020  AM-II
45  Present 23-04-2020  AM-II
... ... ... ...
14  Present 12-04-2020  LMS
13  Absent  18-04-2020  LMS
11  Absent  19-04-2020  LMS
10  Present 25-04-2020  LMS
9   Present 26-04-2020  LMS

我正在使用 python 的 pandas 库来计算每个唯一主题出现“出席”的次数和“缺席”的次数,但我无法这样做。这就是我正在做的事情。

data=pd.read_csv("data1.csv") 
  
#sorting data frame by Team and then By names 
data.sort_values(["Subject", "Date"], axis=0, 
                 ascending=True, inplace=True) 
p = 0
a = 0
total = 0
attpercent = {}
data.set_index(["Subject"], inplace = True, 
                            append = True, drop = False)
temp = ""
data = data.infer_objects()
for Subject, Attend in data.iterrows()
    if(temp == ""):
        temp = Subject
        if Attend == "Present":
                p = p + 1
        else:
            a = a + 1
    else:
        if(temp == Subject):
            if Attend == "Present":
                p = p + 1
            else:
                a = a + 1
        else:
            total = a + p
            attpercent[temp] = (p * 100) / total
            a = 0
            p = 0
            temp = Subject 
            if Attend == "Present":
                p = p + 1
            else:
                a = a + 1
                
print(attpercent)

显示错误:

 TypeError                                 Traceback (most recent call last)
<ipython-input-65-9d7243427e5f> in <module>
     18 data = data.infer_objects()
     19 for Subject, Attend in data.iterrows():
---> 20     Attend = str(Attend)
     21     if(temp == ""):
     22         temp = Subject

TypeError: 'Series' object is not callable

我是第一次使用 pandas,所以对它了解不多。我尝试使用infer_objectsastypes() 转换列的类型,但仍然出现相同的错误。请帮忙。

【问题讨论】:

  • Iterrows() 不返回列它将返回行,您应该使用for index, row in data.iterrow() tehn 您可以通过row[Attend]row['Subject'] 访问列值

标签: python pandas numpy dataframe import-from-excel


【解决方案1】:

您应尽量避免 for 循环和迭代,并熟悉 .groupby.pivot_table.unstackpandas 方法。对于这个特殊问题,您可以使用.groupby.size,然后使用.unstack 将行移至列,并以良好的格式获取数据,以准备计算出勤率。

df = df.groupby(['Subject','Attend']).size().reset_index() \
       .set_index(['Subject', 'Attend']) \
       .unstack(1).fillna(0).astype(int)
df.columns = df.columns.droplevel(0)
df['Attendance'] = df['Present'] / ( df['Present'] + df['Absent'])
df

输出:

Attend  Absent  Present Attendance
Subject         
AM-II   0       5       1.0
LMS     2       3       0.6

更详细的解释。

在相关列上的.groupbysize 计算出现次数之后,使用.set_index(['Subject', 'Attend']),我将这两列设置在索引上,为下一步做准备。接下来,我将Attend 移动到标题中,以将此数据集放入一个很好的矩阵格式中,例如 Excel 数据透视表。使用.unstack(1),我将使用我刚刚设置的第二个索引列(记住python从0开始,所以1现在使用第二个索引列并将它们作为我的标题,本质上是从行到列重塑数据框以一种非常方便的方式。如果我使用.unstack(0),它会将Subject 移动到标题中,这不会以我们想要的方式可视化数据。

最后,df.columns = df.columns.droplevel(0) 从 Multiindex 中删除一个级别以使其看起来更清晰,然后 Attendance 的计算非常简单,它将 # of Present 除以 Total 以获得每个主题的出勤率。


假设,完整数据包括学生的另一列。根据第一个示例,您可能可以从这里尝试找出如何做到这一点,但这是您可以做的。

输入:

    Attend  Date       Subject  Student
96  Present 09-04-2020  AM-II   Kathy
69  Present 16-04-2020  AM-II   John
61  Present 20-04-2020  AM-II   John
49  Present 22-04-2020  AM-II   John
45  Present 23-04-2020  AM-II   Kathy
14  Present 12-04-2020  LMS     Kathy
13  Absent  18-04-2020  LMS     Kathy
11  Absent  19-04-2020  LMS     John
10  Present 25-04-2020  LMS     Kathy
9   Present 26-04-2020  LMS     John

代码:

df = df.groupby(['Student','Subject','Attend']).size().reset_index().set_index(['Student','Subject', 'Attend']).unstack(2).fillna(0).astype(int)
df.columns = df.columns.droplevel(0)
df['Attendance'] = df['Present'] / ( df['Present'] + df['Absent'])
df

        Attend  Absent  Present Attendance
Student Subject         
John    AM-II   0       3       1.000000
        LMS     1       1       0.500000
Kathy   AM-II   0       2       1.000000
        LMS     1       2       0.666667

代码几乎相同。您只需将额外的列Student 包含在.groupby.set_index() 中,并将.unstack1 增加到2,因为Attend 列现在是@987654351 指定的第三个index 列@。然后,将drop_level(1) 更改为drop_level(0),因为索引上有两列。

最后,如果您想要一个没有多重索引的干净数据集,只需执行df = df.reset_index() 作为最后一步即可返回:

Attend  Student Subject Absent  Present Attendance
0       John    AM-II   0       3       1.000000
1       John    LMS     1       1       0.500000
2       Kathy   AM-II   0       2       1.000000
3       Kathy   LMS     1       2       0.666667

【讨论】:

  • 感谢您提供这样的解释性答案。但是我不明白为什么没有显示“日期”列?当我尝试将其放入 groupby() 时, df['Attendance'] 不会显示正确答案,因为它会显示每天的出席率。如果假设我想在特定日期之后计算出勤率,我该怎么做?
  • @YashSethia ,'Date' 不包含在 groupby 中,因此它不包含在最终结果中,但是您是正确的,无论如何您都不想 groupby 日期。要在特定日期之后进行过滤,请执行“df.loc[df[‘Date’] > ‘09-04-2020’.groupby’...。您可以将 ‘09-04-2020’ 替换为任何日期”。希望这可以帮助。如果有帮助,请点赞并采纳。
  • 我试着写这个' data = data.loc[data["Date"] > "01-05-2020"].groupby(['Subject', 'Attend']).size( ).reset_index() \ .set_index(['Subject','Attend']) \ .unstack(1).fillna(0).astype(int) ' 但它不起作用。我仍然得到所有日期的百分比
  • @YashSerthia 在 groupby 之前尝试 data['Date'] = pd.to_datetime(data['Date'],dayfirst=True) ... 然后尝试 ... data = data.loc [data["Date"] > "2020-05-01"] 如果有错误,请贴出来。
  • 我做了 data["Date"] = pd.to_datetime(data['Date'], dayfirst = True) data = data.loc[data['Date'] > "01-05- 2020”] 但什么也没发生。输出仍然是整个数据。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-10
  • 1970-01-01
相关资源
最近更新 更多