我有一堆调查数据按每个问题的每个选择的答案数量(多项选择题)进行细分。我有几个不同的课程,学期,部分等的每个摘要之一。不幸的是,我的所有数据都是在PDF打印输出给我,我无法获得数字数据。从好的方面来说,这意味着我可以自由统治格式化我的数据文件,但是我需要这样才能将它导入到Pandas中。
如何将我的数据导入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
如果我的数据已经在Pandas中,那么基本上我有.value_counts()
个结果。请注意,问题并不总是具有相同数量的选项(类别),并且它们并不总是具有相同数量的响应者。对于多个课程编号,学期和部分,我会得到类似的结果。
类别A
,B
,C
等只是占位符,用于表示实际数据中每个响应类别的标签。
另外,我必须手动将所有这些输入到某些内容中,所以我并不担心阅读上面的特定文件格式,它只是代表我在我面前的实际打印输出上的内容。
我想通过告诉Pandas在每个问题的每个响应类别中有多少来重新创建Pandas中的响应数据。基本上我想要一个看起来像上面的响应数据的Excel文件或CSV,以及一个看起来像的Pandas DataFrame:
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
的人也没有选择选项X
代表问题2.我只想让每个结果的数量显示相同,而我的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")
这有几个问题。首先,我有成千上万的响应,所以创建所有这些行将花费太长时间。我更喜欢紧凑的方法,直接记录每个响应的数量,然后将其导入Pandas。
其次,当我对每个问题没有相同数量的回答时,这会变得有点尴尬。首先,为了节省输入每个响应的时间,我只是在该值与上一行不同时在列中放置一个值,然后使用.ffill()
来转发填充Pandas DataFrame中的值。问题在于所有NaN
值都已填满,因此对于不同的问题我不能有不同数量的回复。
我与第一次在Excel中记录数据的想法没有结合,所以如果有更简单的方式使用别的东西,我都是耳朵。
如果还有其他方式来看待这个比我在这里尝试更有意义的问题,我也愿意听到这个问题。
我稍微切换了一个齿轮并制作了一个Excel文件,其中每个工作表都是一个调查摘要,前几列确定了Course
,Semester
,Section
,{{1}等等,然后我有一列可能的Year
类别。文件的其余部分包含每个问题的列,然后是与匹配该问题的响应相对应的每行中的响应数。然后我导入每个工作表并连接:
Response
这似乎有效,但我最终得到了一张非常丑陋的表格(对于所有与每个问题实际上并不对应的回复,都有很多NaN)。我可以通过以下方式绘制任何一个问题的结果:
df = [pd.read_excel("filename", sheetname=i, index_col=range(0,7)) for i in range(1,3)]
df = pd.concat(df)
我觉得必须有更好的方法来做到这一点,可能有多个索引或某种3D数据结构......
答案 0 :(得分: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]
并将它们压缩在一起:
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
我把它们放在(课程,学期,部分)的另一个词典中 - > DataFrame然后连接并找出从大型MultiIndex dataFrame到哪里去的地方...