【发布时间】:2023-03-31 09:35:01
【问题描述】:
我正在尝试绘制用户在一天中的特定时间发推文的次数。我计划将这些绘制在一个直方图/条形图上,其中包含 24 个“箱”——每小时一个。
我将 Pandas 数据框中的数据分为两列 - 推文和推文时间(作为日期时间对象)。
我已将时间列转换为 Pandas 时间,但是我很难正确绘制。如果我将 bin 的值设置为 24,那么我会得到下面的图表 (here),它看起来不正确。首先图表看起来不对,其次 x 轴的格式很糟糕。
我想尝试解决这两个问题。首先数据没有正确绘制,其次水平轴格式不正确。
我使用 Google 表格绘制了数据,正确的图表应该类似于 this。我不介意这些值是总体积的百分比还是绝对体积。
可以在此处找到生成图的代码。 generate_data.py 和 plot_data.py
非常感谢任何帮助。
plot_data.py
import datetime
import matplotlib.dates as mdates
import matplotlib.pyplot as plt
import pandas as pd
import random
import generate_data
screen_name = "@joebiden"
data = generate_data.get_data(screen_name, save_output=True)
df = pd.DataFrame(data)
df["Time"]= pd.to_datetime(data["Time"], format="%H:%M")
fig, ax = plt.subplots(1,1)
bin_list = [datetime.time(x) for x in range(24)]
ax.hist(df["Time"], bins=24, color='lightblue')
plt.show()
generate_data.py
import json
import re
from datetime import datetime
import tweepy
import common_words
import twitter_auth
def create_connection():
auth = tweepy.OAuthHandler(twitter_auth.CONSUMER_KEY, twitter_auth.CONSUMER_SECRET)
auth.set_access_token(twitter_auth.ACCESS_KEY, twitter_auth.ACCESS_SECRET)
return tweepy.API(auth, wait_on_rate_limit=True, wait_on_rate_limit_notify=True)
def retrieve_next_set_of_tweets(screen_name, api, count,max_id):
'''Return next 200 user tweets'''
return api.user_timeline(screen_name=screen_name,count=count, tweet_mode='extended', max_id=max_id)
def get_tweet_times(screen_name, api):
user_tweet_count = api.get_user(screen_name).statuses_count
all_tweets = {'Tweet':[], 'Time':[]}
block_of_tweets = api.user_timeline(screen_name=screen_name,count=200, tweet_mode='extended')
all_tweets["Tweet"].extend([tweet.full_text for tweet in block_of_tweets])
all_tweets["Time"].extend([tweet.created_at for tweet in block_of_tweets])
oldest = block_of_tweets[-1].id - 1
while block_of_tweets:
try:
block_of_tweets = retrieve_next_set_of_tweets(screen_name, api, 200, oldest)
oldest = block_of_tweets[-1].id - 1
except IndexError: #Reached limit of 3245
pass
# all_tweets.update({tweet.full_text: tweet.created_at.time() for tweet in block_of_tweets})
all_tweets["Tweet"].extend([tweet.full_text for tweet in block_of_tweets])
all_tweets["Time"].extend([tweet.created_at for tweet in block_of_tweets])
return all_tweets
def get_all_tweets(screen_name, api):
user_tweet_count = api.get_user(screen_name).statuses_count
all_tweets = []
block_of_tweets = api.user_timeline(screen_name=screen_name,count=200, tweet_mode='extended')
all_tweets.extend([tweet.full_text for tweet in block_of_tweets])
oldest = block_of_tweets[-1].id - 1
while block_of_tweets:
try:
block_of_tweets = retrieve_next_set_of_tweets(screen_name, api, 200, oldest)
oldest = block_of_tweets[-1].id - 1
except IndexError: #Reached limit of 3245
pass
all_tweets.extend([tweet.full_text for tweet in block_of_tweets])
return all_tweets
def parse_all_tweets(tweet_list, max_words_to_show=50):
tweet_dict = {}
regex = re.compile('[^a-zA-Z ]')
for tweet in tweet_list:
text = regex.sub("", tweet).lower().strip().split()
for word in text:
if word in common_words.MOST_COMMON_ENGLISH_WORDS: continue
if word in tweet_dict.keys():
tweet_dict[word] += 1
else:
if len(tweet_dict.items()) == max_words_to_show:
return tweet_dict
tweet_dict[word] = 1
return tweet_dict
def get_data(screen_name, words_or_times="t", save_output=False):
api = create_connection()
print(f"...Getting max of 3245 tweets for {screen_name}...")
if words_or_times == "t":
all_tweets = get_tweet_times(screen_name, api)
suffix = "tweet_times"
elif words_or_times == "w":
suffix = "ranked_words"
parsed_tweets = parse_all_tweets(get_all_tweets(screen_name, api))
parsed_tweets = {k:v for k,v in sorted(parsed_tweets.items(), key=lambda item: item[1], reverse=True)}
else:
return "...Error. Please enter 't' or 'w' to signify 'times' or 'words'."
if save_output:
f_name = f"{screen_name}_{suffix}.json"
with open(f_name, "w") as f:
json.dump(all_tweets if words_or_times == "t" else parsed_tweets, f, indent=4, default=str)
print(f"...Complete! File saved as '{f_name}'")
return all_tweets if words_or_times == "t" else parsed_tweets
if __name__ == "__main__":
get_data(screen_name="@joebiden", save_output=True)
【问题讨论】:
-
能给几行
df = pd.DataFrame(data)吗?另外,请检查您确实有日期。 -
这里是 df 的前 5 行。 0 RT @Transition46:我们团结一致... 2020-11-08 14:28:23 1 发自内心:谢谢。 https:... 2020-11-08 02:20:00 2 一个国家团结起来。\n\n一个国家加强了。\n\n... 2020-11-08 02:10:00 3 全心全意稳定双手,带着信念... 2020-11-08 02:08:00 4 今晚,全世界都在注视着美国。 ... 2020-11-08 02:05:00```
-
当我输出 df["Time"] 的前 5 条记录时,我得到以下信息。它们是
但仍显示日期和时间,即使我尝试仅在 plot_data.py 的第 14 行将它们格式化为时间。 0 2020-11-08 14:28:23 1 2020-11-08 02:20:00 2 2020-11-08 02:10:00 3 2020-11-08 02:08:00 4 2020-11-08 02:05:00
标签: python pandas matplotlib plot