我正在使用pandas从Twitter数据集执行一些字符串匹配。
我已导入推文CSV并使用日期编制索引。然后我创建了一个包含文本匹配的新列:
In [1]:
import pandas as pd
indata = pd.read_csv('tweets.csv')
indata.index = pd.to_datetime(indata["Date"])
indata["matches"] = indata.Tweet.str.findall("rudd|abbott")
only_results = pd.Series(indata["matches"])
only_results.head(10)
Out[1]:
Date
2013-08-06 16:03:17 []
2013-08-06 16:03:12 []
2013-08-06 16:03:10 []
2013-08-06 16:03:09 []
2013-08-06 16:03:08 []
2013-08-06 16:03:07 []
2013-08-06 16:03:07 [abbott]
2013-08-06 16:03:06 []
2013-08-06 16:03:02 []
2013-08-06 16:03:00 [rudd]
Name: matches, dtype: object
我想要的最终结果是按日/月分组的数据框,我可以将不同的搜索字词绘制为列,然后绘制。
我在另一个SO答案(https://stackoverflow.com/a/16637607/2034487)上看到了完美的解决方案,但在尝试申请这个系列时,我得到了一个例外:
In [2]: only_results.apply(lambda x: pd.Series(1,index=x)).fillna(0)
Out [2]: Exception - Traceback (most recent call last)
...
Exception: Reindexing only valid with uniquely valued Index objects
我真的希望能够应用数据框中的更改来应用和重新应用groupby条件并有效地执行绘图 - 并且希望了解有关.apply()方法如何工作的更多信息。
提前致谢。
成功解答后更新
问题在于我没见过的“匹配”栏中的重复项。我遍历该列以删除重复项,然后使用上面链接的@Jeff原始解决方案。这是成功的,我现在可以在生成的系列中使用.groupby()来查看每日,每小时等趋势。以下是结果图的一个示例:
In [3]: successful_run = only_results.apply(lambda x: pd.Series(1,index=x)).fillna(0)
In [4]: successful_run.groupby([successful_run.index.day,successful_run.index.hour]).sum().plot()
Out [4]: <matplotlib.axes.AxesSubplot at 0x110b51650>
答案 0 :(得分:1)
你有一些重复的结果(例如Rudd在一条推文中出现不止一次),因此是例外(见下文)。
我认为最好计算出现次数而不是来自findall的列表(pandas数据结构不是为了包含列表而设计的,尽管str.findall使用它们。) 我建议使用这样的东西:
In [1]: s = pd.Series(['aa', 'aba', 'b'])
In [2]: pd.DataFrame({key: s.str.count(key) for key in ['a', 'b']})
Out[2]:
a b
0 2 0
1 2 1
2 0 1
注意(由于在前两行中找到重复的'a'的例外):
In [3]: s.str.findall('a').apply(lambda x: pd.Series(1,index=x)).fillna(0)
#InvalidIndexError: Reindexing only valid with uniquely valued Index objects
答案 1 :(得分:1)
首先重置索引,然后使用您提到的解决方案:
In [28]: s
Out[28]:
Date
2013-08-06 16:03:17 []
2013-08-06 16:03:12 []
2013-08-06 16:03:10 []
2013-08-06 16:03:09 []
2013-08-06 16:03:08 []
2013-08-06 16:03:07 []
2013-08-06 16:03:07 [abbott]
2013-08-06 16:03:06 []
2013-08-06 16:03:02 []
2013-08-06 16:03:00 [rudd]
Name: matches, dtype: object
In [29]: df = s.reset_index()
In [30]: df.join(df.matches.apply(lambda x: Series(1, index=x)).fillna(0))
Out[30]:
Date matches abbott rudd
0 2013-08-06 16:03:17 [] 0 0
1 2013-08-06 16:03:12 [] 0 0
2 2013-08-06 16:03:10 [] 0 0
3 2013-08-06 16:03:09 [] 0 0
4 2013-08-06 16:03:08 [] 0 0
5 2013-08-06 16:03:07 [] 0 0
6 2013-08-06 16:03:07 [abbott] 1 0
7 2013-08-06 16:03:06 [] 0 0
8 2013-08-06 16:03:02 [] 0 0
9 2013-08-06 16:03:00 [rudd] 0 1
除非你有DatetimeIndex
的明确用例(通常涉及某种类型的重新采样,并且没有重复),否则最好将日期放入专栏中,因为它比将其保留为列更灵活。索引,特别是如果所述索引有重复的话。
就apply
方法而言,它对于不同的对象略有不同。例如,默认情况下,DataFrame.apply()
会在列中应用传入的可调用对象,但您可以传递axis=1
以沿行应用它。
Series.apply()
将传入的callable应用于Series
实例的每个元素。在@Jeff提供的非常聪明的解决方案的情况下,发生的事情如下:
In [12]: s
Out[12]:
Date
2013-08-06 16:03:17 []
2013-08-06 16:03:12 []
2013-08-06 16:03:10 []
2013-08-06 16:03:09 []
2013-08-06 16:03:08 []
2013-08-06 16:03:07 []
2013-08-06 16:03:07 [abbott]
2013-08-06 16:03:06 []
2013-08-06 16:03:02 []
2013-08-06 16:03:00 [rudd]
Name: matches, dtype: object
In [13]: pd.lib.map_infer(s.values, lambda x: Series(1, index=x)).tolist()
Out[13]:
[Series([], dtype: int64),
Series([], dtype: int64),
Series([], dtype: int64),
Series([], dtype: int64),
Series([], dtype: int64),
Series([], dtype: int64),
abbott 1
dtype: int64,
Series([], dtype: int64),
Series([], dtype: int64),
rudd 1
dtype: int64]
In [14]: pd.core.frame._to_arrays(_13, columns=None)
Out[14]:
(array([[ nan, nan, nan, nan, nan, nan, 1., nan, nan, nan],
[ nan, nan, nan, nan, nan, nan, nan, nan, nan, 1.]]),
Index([u'abbott', u'rudd'], dtype=object))
Series
中的每个空Out[13]
的值都为nan
,表示我们的任何一个列索引都没有值。在这种情况下,该索引为Index([u'abbott', u'rudd'], dtype=object)
。如果 列索引处的值,则保留它。
请记住,这些是用户通常不必担心的低级详细信息。我很好奇,所以我跟着代码的踪迹。