EDA: Misinformation

# Setup - Run only once per Kernel App
%conda install openjdk -y

# install PySpark
%pip install pyspark==3.2.0

# restart kernel
from IPython.core.display import HTML
HTML("<script>Jupyter.notebook.kernel.restart()</script>")
Collecting package metadata (current_repodata.json): done
Solving environment: done


==> WARNING: A newer version of conda exists. <==
  current version: 23.3.1
  latest version: 24.3.0

Please update conda by running

    $ conda update -n base -c defaults conda

Or to minimize the number of packages updated during conda update use

     conda install conda=24.3.0



## Package Plan ##

  environment location: /opt/conda

  added / updated specs:
    - openjdk


The following packages will be downloaded:

    package                    |            build
    ---------------------------|-----------------
    ca-certificates-2024.3.11  |       h06a4308_0         127 KB
    certifi-2024.2.2           |  py310h06a4308_0         159 KB
    openjdk-11.0.13            |       h87a67e3_0       341.0 MB
    ------------------------------------------------------------
                                           Total:       341.3 MB

The following NEW packages will be INSTALLED:

  openjdk            pkgs/main/linux-64::openjdk-11.0.13-h87a67e3_0 

The following packages will be UPDATED:

  ca-certificates    conda-forge::ca-certificates-2023.11.~ --> pkgs/main::ca-certificates-2024.3.11-h06a4308_0 
  certifi            conda-forge/noarch::certifi-2023.11.1~ --> pkgs/main/linux-64::certifi-2024.2.2-py310h06a4308_0 



Downloading and Extracting Packages
ca-certificates-2024 | 127 KB    |                                       |   0% 
openjdk-11.0.13      | 341.0 MB  |                                       |   0% 

certifi-2024.2.2     | 159 KB    |                                       |   0% 
ca-certificates-2024 | 127 KB    | ##################################### | 100% 

ca-certificates-2024 | 127 KB    | ##################################### | 100% 

certifi-2024.2.2     | 159 KB    | ##################################### | 100% 
openjdk-11.0.13      | 341.0 MB  | #6                                    |   4% 
openjdk-11.0.13      | 341.0 MB  | ###2                                  |   9% 
openjdk-11.0.13      | 341.0 MB  | #####                                 |  14% 
openjdk-11.0.13      | 341.0 MB  | ######7                               |  18% 
openjdk-11.0.13      | 341.0 MB  | ########5                             |  23% 
openjdk-11.0.13      | 341.0 MB  | ##########1                           |  27% 
openjdk-11.0.13      | 341.0 MB  | ###########8                          |  32% 
openjdk-11.0.13      | 341.0 MB  | #############5                        |  37% 
openjdk-11.0.13      | 341.0 MB  | ###############1                      |  41% 
openjdk-11.0.13      | 341.0 MB  | ################5                     |  45% 
openjdk-11.0.13      | 341.0 MB  | ##################2                   |  49% 
openjdk-11.0.13      | 341.0 MB  | ###################7                  |  53% 
openjdk-11.0.13      | 341.0 MB  | #####################2                |  58% 
openjdk-11.0.13      | 341.0 MB  | #######################               |  62% 
openjdk-11.0.13      | 341.0 MB  | ########################6             |  67% 
openjdk-11.0.13      | 341.0 MB  | ##########################2           |  71% 
openjdk-11.0.13      | 341.0 MB  | ###########################9          |  76% 
openjdk-11.0.13      | 341.0 MB  | #############################7        |  80% 
openjdk-11.0.13      | 341.0 MB  | ###############################4      |  85% 
openjdk-11.0.13      | 341.0 MB  | #################################     |  89% 
openjdk-11.0.13      | 341.0 MB  | ##################################6   |  94% 
openjdk-11.0.13      | 341.0 MB  | ####################################2 |  98% 
                                                                                
                                                                                

                                                                                
Preparing transaction: done
Verifying transaction: done
Executing transaction: done

Note: you may need to restart the kernel to use updated packages.
Collecting pyspark==3.2.0
  Using cached pyspark-3.2.0-py2.py3-none-any.whl
Collecting py4j==0.10.9.2 (from pyspark==3.2.0)
  Using cached py4j-0.10.9.2-py2.py3-none-any.whl.metadata (1.3 kB)
Using cached py4j-0.10.9.2-py2.py3-none-any.whl (198 kB)
Installing collected packages: py4j, pyspark
Successfully installed py4j-0.10.9.2 pyspark-3.2.0
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv

[notice] A new release of pip is available: 23.3.1 -> 24.0
[notice] To update, run: pip install --upgrade pip
Note: you may need to restart the kernel to use updated packages.
# Import pyspark and build Spark session
from pyspark.sql import SparkSession

spark = (
    SparkSession.builder.appName("PySparkApp")
    .config("spark.jars.packages", "org.apache.hadoop:hadoop-aws:3.2.2")
    .config(
        "fs.s3a.aws.credentials.provider",
        "com.amazonaws.auth.ContainerCredentialsProvider",
    )
    .getOrCreate()
)

print(spark.version)
Warning: Ignoring non-Spark config property: fs.s3a.aws.credentials.provider
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.apache.spark.unsafe.Platform (file:/opt/conda/lib/python3.10/site-packages/pyspark/jars/spark-unsafe_2.12-3.2.0.jar) to constructor java.nio.DirectByteBuffer(long,int)
WARNING: Please consider reporting this to the maintainers of org.apache.spark.unsafe.Platform
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
Ivy Default Cache set to: /root/.ivy2/cache
The jars for the packages stored in: /root/.ivy2/jars
org.apache.hadoop#hadoop-aws added as a dependency
:: resolving dependencies :: org.apache.spark#spark-submit-parent-ccf93f42-0399-45de-ba01-134ccb671968;1.0
    confs: [default]
    found org.apache.hadoop#hadoop-aws;3.2.2 in central
    found com.amazonaws#aws-java-sdk-bundle;1.11.563 in central
:: resolution report :: resolve 659ms :: artifacts dl 27ms
    :: modules in use:
    com.amazonaws#aws-java-sdk-bundle;1.11.563 from central in [default]
    org.apache.hadoop#hadoop-aws;3.2.2 from central in [default]
    ---------------------------------------------------------------------
    |                  |            modules            ||   artifacts   |
    |       conf       | number| search|dwnlded|evicted|| number|dwnlded|
    ---------------------------------------------------------------------
    |      default     |   2   |   0   |   0   |   0   ||   2   |   0   |
    ---------------------------------------------------------------------
:: retrieving :: org.apache.spark#spark-submit-parent-ccf93f42-0399-45de-ba01-134ccb671968
    confs: [default]
    0 artifacts copied, 2 already retrieved (0kB/15ms)
24/04/05 22:23:05 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Using Spark's default log4j profile: org/apache/spark/log4j-defaults.properties
Setting default log level to "WARN".
To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).
24/04/05 22:23:07 WARN Utils: Service 'SparkUI' could not bind on port 4040. Attempting port 4041.
:: loading settings :: url = jar:file:/opt/conda/lib/python3.10/site-packages/pyspark/jars/ivy-2.5.0.jar!/org/apache/ivy/core/settings/ivysettings.xml
3.2.0
%%time
import time
import sagemaker
from sagemaker.spark.processing import PySparkProcessor

# Setup the PySpark processor to run the job. Note the instance type and instance count parameters. SageMaker will create these many instances of this type for the spark job.
role = sagemaker.get_execution_role()
spark_processor = PySparkProcessor(
    base_job_name="sm-spark-project",
    framework_version="3.3",
    role=role,
    instance_count=8,
    instance_type="ml.m5.xlarge",
    max_runtime_in_seconds=3600,
)

# s3 paths
session = sagemaker.Session()
bucket = session.default_bucket()
output_prefix_logs = f"spark_logs"

# modify this comma separated list to choose the subreddits of interest

sr_list = ["climateskeptics", "conspiracy", "climatechange"]


subreddits = ", ".join(sr_list)
configuration = [
    {
        "Classification": "spark-defaults",
        "Properties": {"spark.executor.memory": "12g", "spark.executor.cores": "4"},
    }
]
sagemaker.config INFO - Not applying SDK defaults from location: /etc/xdg/sagemaker/config.yaml
sagemaker.config INFO - Not applying SDK defaults from location: /root/.config/sagemaker/config.yaml
sagemaker.config INFO - Not applying SDK defaults from location: /etc/xdg/sagemaker/config.yaml
sagemaker.config INFO - Not applying SDK defaults from location: /root/.config/sagemaker/config.yaml
sagemaker.config INFO - Not applying SDK defaults from location: /etc/xdg/sagemaker/config.yaml
sagemaker.config INFO - Not applying SDK defaults from location: /root/.config/sagemaker/config.yaml
sagemaker.config INFO - Not applying SDK defaults from location: /etc/xdg/sagemaker/config.yaml
sagemaker.config INFO - Not applying SDK defaults from location: /root/.config/sagemaker/config.yaml
CPU times: user 3.19 s, sys: 317 ms, total: 3.51 s
Wall time: 3.66 s
## Copying csv file to your bucket 
#!aws s3 cp ../data/csv/blogs_and_CTTs.csv s3://{bucket}/project/
upload: ../data/csv/blogs_and_CTTs.csv to s3://sagemaker-us-east-1-283702907751/project/blogs_and_CTTs.csv
from pyspark.sql.functions import col, length, lower as pslower, month, year, when, udf
import pyspark.sql.functions as F
import pandas as pd
from functools import reduce
from pyspark.sql import DataFrame

from pyspark.sql.types import (
    ArrayType,
    BooleanType,
    DoubleType,
    IntegerType,
    StringType,
    StructField,
    StructType,
)
def contains_any(string, terms):
    if type(string) == str:
        matched_terms = [x for x in terms if x in string.lower()]
        if matched_terms:
            return ', '.join(matched_terms)  # Return matched terms as a string
    
    return None

#skeptic_sites_df = pd.read_csv('../data/csv/blogs_and_CTTs.csv')
skeptic_sites_df = pd.read_csv(f's3a://{bucket}/project/blogs_and_CTTs.csv')
skeptic_sites = skeptic_sites_df.website.tolist()

contains_any_site = udf(lambda x: contains_any(x, skeptic_sites), StringType())
submissions_dfs = [spark.read.parquet(f"s3a://{bucket}/project/submissions/yyyy={yyyy}/",
                                      header=True).filter(col("subreddit").isin(["climateskeptics", "conspiracy", "climatechange"])) 
       for yyyy in [2021, 2022, 2023]]

submissions_raw = reduce(DataFrame.unionAll, submissions_dfs)
submissions_cols = ['subreddit', 'title', 'url', 'author', 'num_comments', 'score', 'created_utc']
submissions = submissions_raw.select(submissions_cols)\
                             .withColumn("month", month(col("created_utc")))\
                             .withColumn("year", year(col("created_utc")))
submissions.show()
+---------------+--------------------+--------------------+--------------------+------------+-----+-------------------+-----+----+
|      subreddit|               title|                 url|              author|num_comments|score|        created_utc|month|year|
+---------------+--------------------+--------------------+--------------------+------------+-----+-------------------+-----+----+
|     conspiracy|I work for a comp...|https://imgur.com...|     AlarmingBat3610|           1|    1|2021-11-19 01:24:15|   11|2021|
|     conspiracy|Christian Hall, 1...|https://www.reddi...|    One_Evidence8277|          23|    9|2021-11-19 01:25:08|   11|2021|
|     conspiracy|Smallpox/Monkeypo...|https://www.reddi...|             itslesk|          24|  112|2021-11-19 01:25:17|   11|2021|
|climateskeptics|1972: Climate Sci...|https://realclima...|  logicalprogressive|          44|   94|2021-11-19 01:29:13|   11|2021|
|     conspiracy|Hospitalizations ...|https://www.nbcne...|             Drupain|           7|   50|2021-11-19 01:32:07|   11|2021|
|     conspiracy|New York Times en...|https://i.redd.it...|         Settlemente|           5|   14|2021-11-19 01:35:05|   11|2021|
|     conspiracy|I want everyone t...|https://www.reddi...|         rachael7224|          13|    8|2021-11-19 01:35:16|   11|2021|
|     conspiracy|   [deleted by user]|https://www.reddi...|           [deleted]|          74|   88|2021-11-19 01:35:20|   11|2021|
|     conspiracy|Anyone can get ri...|https://i.redd.it...|        GhostofKeeny|          44|  285|2021-11-19 01:36:15|   11|2021|
|     conspiracy|   [deleted by user]|https://www.reddi...|           [deleted]|           2|    2|2021-11-19 01:37:05|   11|2021|
|     conspiracy|Will Walmart be c...|https://i.redd.it...|           [deleted]|           6|    3|2021-11-19 01:37:38|   11|2021|
|     conspiracy|Is this sub a pol...|https://www.reddi...|              cebjmb|          16|    0|2021-11-19 01:40:20|   11|2021|
|     conspiracy|   [deleted by user]|https://www.reddi...|           [deleted]|          12|    3|2021-11-19 01:43:26|   11|2021|
|     conspiracy|Fauci is a crimin...|https://www.reddi...|    ScreenExtensions|           3|   72|2021-11-19 01:47:20|   11|2021|
|     conspiracy|Told you guys, th...|https://i.redd.it...|        JackHavoc161|         141|  163|2021-11-19 01:49:22|   11|2021|
|     conspiracy|To all the fans o...|https://www.reddi...|   TheArbiterOfTooth|          15|    0|2021-11-19 01:51:54|   11|2021|
|     conspiracy|Voting | Noam Cho...|https://youtube.c...|     freewilllibrary|           3|    1|2021-11-19 01:52:13|   11|2021|
|     conspiracy|body language tel...|https://youtu.be/...|         ChabISright|           2|    9|2021-11-19 01:54:49|   11|2021|
|     conspiracy|I have no choice....|https://www.reddi...|       Edmund-Dantes|          37|    2|2021-11-19 01:55:54|   11|2021|
|     conspiracy|Fentanyl overdose...|https://www.reddi...|Leather-Yesterday197|          12|   33|2021-11-19 01:56:31|   11|2021|
+---------------+--------------------+--------------------+--------------------+------------+-----+-------------------+-----+----+
only showing top 20 rows
# applying udf
submissions = submissions.withColumn("skeptic_site", contains_any_site(col("url")))
submissions.show()
[Stage 2:>                                                          (0 + 1) / 1]                                                                                
+---------------+--------------------+--------------------+--------------------+------------+-----+-------------------+-----+----+------------+
|      subreddit|               title|                 url|              author|num_comments|score|        created_utc|month|year|skeptic_site|
+---------------+--------------------+--------------------+--------------------+------------+-----+-------------------+-----+----+------------+
|     conspiracy|They manipulated ...|https://rumble.co...|     MaxHeadroomFlux|          17|    0|2023-01-25 19:45:44|    1|2023|        null|
|     conspiracy|The WEF's Plan to...|https://youtube.c...|   Glutenfreeshampoo|           4|    6|2023-01-25 19:47:36|    1|2023|        null|
|     conspiracy|Biden’s classifie...|https://twitter.c...| Standard-Radish1803|           3|   18|2023-01-25 19:47:41|    1|2023|        null|
|     conspiracy|BEST NUDEs Discor...|https://www.reddi...|           [deleted]|           1|    1|2023-01-25 19:48:53|    1|2023|        null|
|     conspiracy|     Classified docs|https://www.reddi...|         tfletcher20|           2|    0|2023-01-25 19:53:07|    1|2023|        null|
|     conspiracy|#h3-Gate Spiralin...|https://www.youtu...|     VoiceFlamingo-R|          12|    3|2023-01-25 19:54:47|    1|2023|        null|
|     conspiracy|"Congress Again B...|https://www.milit...|       ChamberedEcho|           7|    7|2023-01-25 19:57:44|    1|2023|        null|
|     conspiracy|Most pyramids wer...|https://www.reddi...|Remote-Specialist623|          16|   23|2023-01-25 19:58:27|    1|2023|        null|
|     conspiracy|You wouldn't find...|https://youtu.be/...|  Full-Progress-5877|          37|    0|2023-01-25 20:01:11|    1|2023|        null|
|     conspiracy|Just a simple rem...|https://i.redd.it...|    FuzzyBlankets777|         433| 2421|2023-01-25 20:02:35|    1|2023|        null|
|     conspiracy|     Governor Abbott|https://www.reddi...|       6footreadhead|           0|    1|2023-01-25 20:03:01|    1|2023|        null|
|     conspiracy|Ready to eat ze b...|                    |           [deleted]|           2|    0|2023-01-25 20:03:21|    1|2023|        null|
|     conspiracy|Pro-Vax Dilbert C...|https://www.reddi...|       Lighthouse_56|         104|   48|2023-01-25 20:03:49|    1|2023|        null|
|climateskeptics|                 〰️|https://climatedi...|       greyfalcon333|           1|    1|2023-01-25 20:06:06|    1|2023|        null|
|     conspiracy|Insects as powder...|                    |           [deleted]|           2|    1|2023-01-25 20:07:27|    1|2023|        null|
|     conspiracy|Saw today in Rexe...|https://i.redd.it...|         TheNextPley|           6|    6|2023-01-25 20:12:35|    1|2023|        null|
|     conspiracy|ChatGPT helped me...|https://www.reddi...|      AbstractWealth|           6|    0|2023-01-16 08:04:57|    1|2023|        null|
|     conspiracy|German court seek...|https://twitter.c...|CompetitionMiddle358|          10|   11|2023-01-16 08:11:41|    1|2023|        null|
|     conspiracy|It's truly incred...|https://i.redd.it...|   Razariousnefarian|         656| 1030|2023-01-16 08:14:29|    1|2023|        null|
|     conspiracy|Telegram channel ...|                    |           [deleted]|           1|    1|2023-01-16 08:26:52|    1|2023|        null|
+---------------+--------------------+--------------------+--------------------+------------+-----+-------------------+-----+----+------------+
only showing top 20 rows
# just checking the filter
submissions.filter(col('skeptic_site').isNotNull()).show()
[Stage 4:>                                                          (0 + 1) / 1]                                                                                
+---------------+--------------------+--------------------+------------------+------------+-----+-------------------+-----+----+--------------------+
|      subreddit|               title|                 url|            author|num_comments|score|        created_utc|month|year|        skeptic_site|
+---------------+--------------------+--------------------+------------------+------------+-----+-------------------+-----+----+--------------------+
|climateskeptics|Electric car make...|https://wattsupwi...|logicalprogressive|           8|    5|2023-01-14 23:43:43|    1|2023| wattsupwiththat.com|
|climateskeptics|Who Needs Actual ...|https://notalotof...| LackmustestTester|          28|    7|2023-02-01 17:46:27|    2|2023|notalotofpeoplekn...|
|climateskeptics|Former NOAA Meteo...|https://notricksz...| LackmustestTester|          14|   27|2023-03-03 19:28:31|    3|2023|    notrickszone.com|
|climateskeptics|The Ministry of C...|https://wattsupwi...| LackmustestTester|           8|   17|2023-02-05 00:08:33|    2|2023| wattsupwiththat.com|
|climateskeptics|       Masked Bandit|https://realclima...| LackmustestTester|          24|    1|2023-01-21 17:23:38|    1|2023|realclimatescienc...|
|climateskeptics|Hydrogen Not Like...|https://notricksz...| LackmustestTester|          10|    2|2023-01-21 17:46:03|    1|2023|    notrickszone.com|
|climateskeptics|Measurements Show...|https://notricksz...| LackmustestTester|          22|    5|2023-01-28 17:35:22|    1|2023|    notrickszone.com|
|climateskeptics|                   .|https://www.cfact...|     greyfalcon333|           0|    9|2023-03-09 15:12:08|    3|2023|           cfact.org|
|climateskeptics|A Glaring Inconsi...|https://notricksz...| LackmustestTester|           5|    5|2023-01-12 20:47:38|    1|2023|    notrickszone.com|
|climateskeptics|                  🌐|https://climatech...|     greyfalcon333|           1|    4|2023-01-06 17:22:02|    1|2023|climatechangedisp...|
|climateskeptics|Whale Death Confu...|https://climatech...|     greyfalcon333|           0|    0|2023-03-11 17:42:17|    3|2023|climatechangedisp...|
|climateskeptics|Sea Level Is Stab...|https://wattsupwi...|logicalprogressive|          19|    9|2023-02-08 08:03:29|    2|2023| wattsupwiththat.com|
|climateskeptics|                  🚙|https://wattsupwi...|     greyfalcon333|           0|    0|2023-01-07 02:44:04|    1|2023| wattsupwiththat.com|
|climateskeptics|Former spokespers...|https://wattsupwi...|logicalprogressive|          28|   55|2023-01-26 23:25:24|    1|2023| wattsupwiththat.com|
|climateskeptics|No, Exxon was Wro...|https://junkscien...| LackmustestTester|          53|   10|2023-01-28 18:31:03|    1|2023|     junkscience.com|
|climateskeptics|                  🌐|https://climatech...|     greyfalcon333|           0|    2|2023-03-19 12:45:06|    3|2023|climatechangedisp...|
|climateskeptics|                  🌐|https://www.cfact...|     greyfalcon333|           0|   10|2023-03-19 16:35:40|    3|2023|           cfact.org|
|climateskeptics|How Did Those UKC...|https://notalotof...| LackmustestTester|           2|    5|2023-02-03 18:34:38|    2|2023|notalotofpeoplekn...|
|climateskeptics|Climate Alarmist’...|https://wattsupwi...|logicalprogressive|           5|    6|2023-01-30 04:43:44|    1|2023| wattsupwiththat.com|
|climateskeptics|"Claim: Global fo...|https://tallbloke...|          pr-mth-s|           7|   22|2023-03-09 20:05:31|    3|2023|tallbloke.wordpre...|
+---------------+--------------------+--------------------+------------------+------------+-----+-------------------+-----+----+--------------------+
only showing top 20 rows
submissions_site_group = submissions.filter(col('skeptic_site').isNotNull())\
                         .groupBy('subreddit', 'skeptic_site').agg(F.count('*').alias('posts'),
                                                                   F.countDistinct('author').alias('distinct_authors'),
                                                                   F.sum('num_comments').alias('total_comments'),
                                                                   F.mean('num_comments').alias('average_comments'),
                                                                   F.mean('score').alias('average_score'))
#submissions_site_group.show(truncate = False)
submissions_site_group.toPandas().to_csv("../data/csv/skeptic_site_submissions.csv")
                                                                                
submissions_authors_group = submissions.filter(col('skeptic_site').isNotNull())\
                            .groupBy('subreddit', 'author').agg(F.count('*').alias('posts'),
                                                                F.countDistinct('skeptic_site').alias('distinct_sites'),
                                                                F.sum('num_comments').alias('total_comments'),
                                                                F.mean('num_comments').alias('average_comments'),
                                                                F.mean('score').alias('average_score'))
#submissions_authors_group.show()
submissions_authors_group.toPandas().to_csv("../data/csv/skeptic_site_submissions_authors.csv")
                                                                                
%%writefile ./code/submissions_process.py

# processing job imports
import os
import sys
import logging
import argparse

## pyspark/analysis-related imports
# Import pyspark and build Spark session
from pyspark.sql import SparkSession
from pyspark.sql.functions import col, length, lower as pslower, month, year, when, udf
import pyspark.sql.functions as F
import pandas as pd
from functools import reduce
from pyspark.sql import DataFrame

from pyspark.sql.types import (
    ArrayType,
    BooleanType,
    DoubleType,
    IntegerType,
    StringType,
    StructField,
    StructType,
)
# Import pyspark and build Spark session
logging.basicConfig(format='%(asctime)s,%(levelname)s,%(module)s,%(filename)s,%(lineno)d,%(message)s', level=logging.DEBUG)
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
logger.addHandler(logging.StreamHandler(sys.stdout))

## Defining functions/constants
def contains_any(string, terms): 
    matched_terms = [x for x in terms if x in string.lower()]
    if matched_terms:
        return ', '.join(matched_terms)  # Return matched terms as a string
    else:
        return None  # Return False if no terms match

def main():
    ## processing job-related setup
    spark = SparkSession.builder.appName("PySparkApp").getOrCreate()
    logger.info(f"spark version = {spark.version}")
    
    parser = argparse.ArgumentParser(description="app inputs and outputs")
    parser.add_argument("--bucket", type=str, help="s3 output bucket")
    
    args = parser.parse_args()
    
    # This is needed to save RDDs which is the only way to write nested Dataframes into CSV format
    sc = spark.sparkContext
    sc._jsc.hadoopConfiguration().set(
        "mapred.output.committer.class", "org.apache.hadoop.mapred.FileOutputCommitter"
    )

    ## getting list of conservative blogs/think tanks
    skeptic_sites_df = pd.read_csv(f's3a://{args.bucket}/project/blogs_and_CTTs.csv')
    skeptic_sites = skeptic_sites_df.website.tolist()

    contains_any_site = udf(lambda x: contains_any(x, skeptic_sites), StringType())
    
    ## pulling data from s3
    submissions_dfs = [spark.read.parquet(f"s3a://{bucket}/project/submissions/yyyy={yyyy}/",
                                      header=True).filter(col("subreddit").isin(["climateskeptics", "conspiracy", "climatechange"])) 
                       for yyyy in [2021, 2022, 2023]]
    logger.info("successfully read data")

    ## cleaning
    submissions_raw = reduce(DataFrame.unionAll, submissions_dfs)
    submissions_cols = ['subreddit', 'title', 'url', 'author', 'num_comments', 'score', 'created_utc']
    submissions = submissions_raw.select(submissions_cols)\
                                 .withColumn("month", month(col("created_utc")))\
                                 .withColumn("year", year(col("created_utc")))        
    
    logger.info("clean up successful")
    logger.info(submissions.columns)
    
    ## Building dfs for analyzing skeptic sites
    submissions = submissions.withColumn("skeptic_site", contains_any_site(col("url")))
    submissions_site_group = submissions.filter(col('skeptic_site').isNotNull())\
                         .groupBy('subreddit', 'skeptic_site').agg(F.count('*').alias('posts'),
                                                                   F.countDistinct('author').alias('distinct_authors'),
                                                                   F.sum('num_comments').alias('total_comments'),
                                                                   F.mean('num_comments').alias('average_comments'),
                                                                   F.mean('score').alias('average_score'))

    # save the filtered dataframes so that these files can now be used for future analysis
    submissions_site_group.toPandas().to_csv("../data/csv/skeptic_site_submissions.csv")

    logger.info("saved submissions_site_group")

    ## Grouping by authors
    submissions_authors_group = submissions.filter(col('skeptic_site').isNotNull())\
                            .groupBy('subreddit', 'author').agg(F.count('*').alias('posts'),
                                                                F.countDistinct('skeptic_site').alias('distinct_sites'),
                                                                F.sum('num_comments').alias('total_comments'),
                                                                F.mean('num_comments').alias('average_comments'),
                                                                F.mean('score').alias('average_score'))
    
    submissions_authors_group.toPandas().to_csv("../data/csv/skeptic_site_submissions_authors.csv")
    logger.info(f"saved submissions_authors_group")

    logger.info(f"all done...")
    
if __name__ == "__main__":
    main()
Overwriting ./code/submissions_process.py
spark_processor.run(
    submit_app="./code/submissions_process.py",
    arguments=["--bucket",
            bucket],
    spark_event_logs_s3_uri="s3://{}/{}/spark_event_logs".format(bucket, output_prefix_logs),
    logs=False,
    configuration=configuration
)
INFO:sagemaker:Creating processing-job with name sm-spark-project-2024-04-05-22-08-20-333
.......................................................................*
UnexpectedStatusException: Error for Processing job sm-spark-project-2024-04-05-22-08-20-333: Failed. Reason: AlgorithmError: See job logs for more information
!aws s3 cp s3://{bucket}/project/data
../data/csv/blogs_and_CTTs.csv 

../data/csv/skeptic_site_submissions.csv