用分类数据计数创建一个熊猫数据框

用分类数据计数创建一个熊猫数据框

问题描述:

我有一堆调查数据按每个问题(多项选择题)的每个答案的答复数分解。对于几个不同的课程,学期,部分等,我都有其中的一个摘要。不幸的是,我的所有数据都以PDF格式打印出来,并且我无法获取数字数据。在光明的一面,这意味着我有*统治格式化我的数据文件,但我需要,以便我可以将它导入熊猫。用分类数据计数创建一个熊猫数据框

如何将数据导入到Pandas中,最好不需要逐行复制(每个条目由我的摘要表示)。

数据

我的调查包括几个选择题。每个问题的答案人数选择每个选项。喜欢的东西:

Course Number: 100 
Semester: Spring 
Section: 01 

Question 1 
---------- 
Option A: 27 
Option B: 30 
Option C: 0 
Option D: 2 

Question 2 
---------- 
Option X: 20 
Option Y: 10 

所以基本上我有.value_counts()的结果,如果我的数据已经在大熊猫。请注意,问题并不总是具有相同数量的选项(类别),并且它们并不总是具有相同数量的答复者。我将在多个课程编号,学期和部分中获得类似的结果。

类别A,B,C等只是占位符在这里代表我的实际数据中每个响应类别的标签。

此外,我不得不手动输入所有这些东西,所以我不担心读取上面的特定文件格式,它只是代表了我在实际打印输出上的内容。

目标

我想告诉熊猫多少每个响应类别我对每一个问题的重新创建大熊猫响应数据。基本上我想要一个Excel文件或CSV看起来像上面的响应数据,和熊猫数据框,看起来像:

Course Number Semester Section Q1 Q2 
100    Spring  01  A X 
100    Spring  01  A X 
... (20 identical entries) 
100    Spring  01  A Y 
100    Spring  01  A Y 
... (7 of these) 
100    Spring  01  B Y 
100    Spring  01  B Y 
100    Spring  01  B Y 
100    Spring  01  B N/A (out of Q2 responses) 
... 
100    Spring  01  D N/A 
100    Spring  01  D N/A 

我要指出,我不是在这里再现实际响应数据,因为我有没有办法知道有人为问题1选择D选项并没有为问题2选择选项X。我只是希望每个结果的编号都显示相同,并且对于我的df.count_values()输出基本上给出了我的总结已经说过了。

尝试到目前为止

到目前为止,我可以拿出实际再现一个Excel文件中的每个反应作为自己的行,然后导入此文件,并转换为类最佳:

import pandas as pd 

df = pd.read_excel("filename") 
df["Q1"] = df["Q1"].astype("category") 
df["Q2"] = df["Q2"].astype("category") 

这有几个问题。首先,我有成千上万的回应,因此创建所有这些行将花费太长时间。我更喜欢紧凑的方法,直接记录每个响应的数量,然后将其导入熊猫。

其次,当我对每个问题没有相同数量的响应时,这会变得有点尴尬。首先,为了节省输入每个响应的时间,我只是在该值与上一行不同时将值放入列中,然后使用.ffill()来前向填充Pandas DataFrame中的值。与此相关的问题是,所有NaN值都已填充,所以对于不同的问题,我无法获得不同数量的答复。

我不想结婚的想法,首先在Excel中记录数据,所以如果有更简单的方法使用别的东西,我都是耳朵。

如果还有其他的方式来看待这个问题比我在这里尝试的更有意义,我也很乐意听到这个问题。

编辑:一种工作

的我切换齿轮的位和由Excel文件,其中每个薄片是单层调查概要,第一几列识别CourseSemesterSectionYear等,并那么我有一列可能的Response类别。文件的其余部分包含每个问题的一列,然后每行中对应于与该问题匹配的答复的答复数量。然后我导入每个板并连接:

df = [pd.read_excel("filename", sheetname=i, index_col=range(0,7)) for i in range(1,3)] 
df = pd.concat(df) 

这似乎是工作,但我结束了一个十分可怕的表(许多NaN的对所有不符合实际对每个问题的答复)。我可以种解决这个问题对于像密谋对任何一个问题的结果:

df_grouped = df.groupby("Response", sort=False).aggregate(sum) # group according to response 
df_grouped["Q1"][np.isfinite(df_grouped["Q1"])].plot(kind="bar") # only plot responses that have values 

我觉得必须有一个更好的方式来做到这一点,也许有多个索引或某种3D数据结构...

+0

你从哪里得到pdf,或许他们把它作为一个csv /更好的格式? –

+0

不好意思,我问。我认为链上的某个人可能会这样,但我无法以我可以轻松使用的格式获取实际的报告数据。 – Engineero

+0

它是每个课程的单个文件,在同一个文件中是否有多个学期?多个部分? –

一个搞怪的方式来获取信息是首先拆分-----然后使用正则表达式。

对于每门课程,以便像下面这样:

In [11]: s 
Out[11]: 'Semester: Spring\nSection: 01\nQuestion 1\n----------\nOption A: 27\nOption B: 30\nOption C: 0\nOption D: 2\n\nQuestion 2\n----------\nOption A: 20\nOption B: 10' 

In [12]: blocks = s.split("----------") 

解析出从第一块的信息,请使用正则表达式或刚刚拆分:

In [13]: semester = re.match("Semester: (.*)", blocks[0]).groups()[0] 

In [14]: semester 
Out[14]: 'Spring' 

从每个块解析选项的信息:

def parse_block(lines): 
    d = {} 
    for line in lines: 
     m = re.match("Option ([^:]+): (\d+)", line) 
     if m: 
      d[m.groups()[0]] = int(m.groups()[1]) 
    return d 

In [21]: [parse_block(x.splitlines()) for x in blocks[1:]] 
Out[21]: [{'A': 27, 'B': 30, 'C': 0, 'D': 2}, {'A': 20, 'B': 10}] 

你可以同样拉出问题编号(如果你不知道他们是顺序):

In [22]: questions = [int(re.match(".*Question (\d+)", x, re.DOTALL).groups()[0]) for x in blocks[:-1]] 

In [23]: questions 
Out[23]: [1, 2] 

而这三者一起ZIP:

In [31]: dict(zip(questions, ds)) 
Out[31]: {1: {'A': 27, 'B': 30, 'C': 0, 'D': 2}, 2: {'A': 20, 'B': 10}} 

In [32]: pd.DataFrame(dict(zip(questions, ds))) 
Out[32]: 
    1 2 
A 27 20 
B 30 10 
C 0 NaN 
D 2 NaN 

我把这些在(当然,学期,一节)的另一个字典 - >数据框,然后CONCAT和工作从大的MultiIndex数据框中走出哪里...

+0

很酷,但我希望我的'df.value_counts()'基本上输出你的DataFrame显示的内容。所以我想通过给Pandas每个问题的每个类别的响应数来重现我的DataFrame中的每个响应。 – Engineero

+0

@Engineero我认为你不应该那样做。 –

+0

@Engineero说,这方面可以自己做一个很好的问题。 (“如何解聚熊猫DataFrame”?) –