Data Mining Data.Gov: Statistiken aus FEC-Kandidaten-Zusammenfassungsdateien
Eine der weniger bekannten Funktionen von Solr (zumindest aus meiner Sicht) ist die StatsComponent. Stats ist eine Funktion, die in…
Eine der weniger bekannten Funktionen von Solr (zumindest aus meiner Sicht) ist die StatsComponent. Stats ist eine Funktion, die in Solr 1.4 hinzugefügt wurde und es Solr ermöglicht, verschiedene Statistiken für numerische Felder in Ihren Dokumenten zu berechnen. Sie unterstützt sogar die Möglichkeit, diese Statistiken pro Facettenbeschränkung aus anderen Feldern zu berechnen.
Da die Vorwahlsaison in vollem Gange ist (jedenfalls hier in den USA), demonstrieren wir die Statistikfunktionalität von Solr anhand einiger Daten von Data.Gov. Genauer gesagt, indizieren wir die„2009-2010 Candidate Summary File“ Daten der FEC…
Zusammenfassende Finanzinformationen über Kampagnen für den US-Senat, das US-Repräsentantenhaus und den Präsidenten der Vereinigten Staaten
Das klingt sicherlich so, als ob es einige interessante numerische Daten enthalten sollte, und das„Data Dictionary/Variablenliste“ scheint dies auch zu unterstützen. Aber bevor wir Solr verwenden können, um einige Statistiken aus diesen Daten zu erstellen, müssen wir sie indizieren. Wir beginnen mit dem Abrufen der Daten und werfen einen Blick in….
$ curl -sSL http://www.data.gov/download/1930/xml | xmllint --format - | head -20 <?xml version="1.0"?> <data.fec.gov fecdc_schemaLocation="http://www.fec.gov/data http://www.fec.gov/finance/disclosure/schema/CandidateSummary.xsd"> <title>Candidate Summary</title> <description>Financial information for each candidate who has registered with the FEC or appears on an official state ballot for an election to the U.S. House of Representatives or U.S. Senate during the current two-year election cycle (including special elections).</description> <timestamp>Thu, 06 May 2010 05:05:47 EST</timestamp> <copyright>Copyright 2010, Federal Election Commission.</copyright> <can_sum> <lin_ima>http://images.nictusa.com/cgi-bin/fecimg/?H4NY07011</lin_ima> <can_id>H4NY07011</can_id> <can_nam>ACKERMAN, GARY L.</can_nam> <can_off>H</can_off> <can_off_sta>NY</can_off_sta> <can_off_dis>05</can_off_dis> <can_par_aff>DEM</can_par_aff> <can_inc_cha_ope_sea>INCUMBENT</can_inc_cha_ope_sea> <can_str1>113 DEER RUN</can_str1> <can_str2/> <can_cit>ROSLYN HEIGHTS</can_cit> <can_sta>NY</can_sta> <can_zip>11577</can_zip>
Wir haben noch nicht viele numerische Daten gesehen, aber wir haben zumindest überprüft, dass die Daten mit den Metadaten übereinstimmen, die wir erhalten haben – ein wichtiger erster Schritt. Jetzt können wir also unseren grundlegenden Solr-Index einrichten. Der erste Schritt besteht darin, eine einfache Konfigurationsdatei für den DataImportHandler (DIH) zu erstellen. DIH erleichtert die Indizierung aus einer Vielzahl von Quellen, einschließlich XML-Dateien. Solr 1.4 wird mit einer Beispieldatei „rss-data-config.xml“ geliefert, die die Indizierung eines RSS-Feeds demonstriert. Wir werden diese Datei als Vorlage für die Erstellung unserer „fec-data-config.xml“ verwenden ….
<dataConfig> <dataSource type="HttpDataSource" encoding="UTF-8" /> <document> <entity name="data-gov-1930" pk="id" url="http://www.data.gov/download/1930/xml" processor="XPathEntityProcessor" forEach="/data.fec.gov/can_sum" transformer="DateFormatTransformer,RegexTransformer"> <field column="id" xpath="/data.fec.gov/can_sum/can_id" /> <field column="name" xpath="/data.fec.gov/can_sum/can_nam" /> <field column="url" xpath="/data.fec.gov/can_sum/lin_ima" /> <field column="office" xpath="/data.fec.gov/can_sum/can_off" /> <field column="state" xpath="/data.fec.gov/can_sum/can_off_sta" /> <field column="district" xpath="/data.fec.gov/can_sum/can_off_dis" /> <field column="party" xpath="/data.fec.gov/can_sum/can_par_aff" /> <field column="candidate_type" xpath="/data.fec.gov/can_sum/can_inc_cha_ope_sea" /> <field column="itemized_individual_contrib" xpath="/data.fec.gov/can_sum/ind_ite_con" regex="$|,|(.d{1,2})" replaceWith="" /> <field column="unitemized_individual_contrib" xpath="/data.fec.gov/can_sum/ind_uni_con" regex="$|,|(.d{1,2})" replaceWith="" /> <field column="individual_contrib" xpath="/data.fec.gov/can_sum/ind_con" regex="$|,|(.d{1,2})" replaceWith="" /> <field column="party_contrib" xpath="/data.fec.gov/can_sum/par_com_con" regex="$|,|(.d{1,2})" replaceWith="" /> <field column="committees_contrib" xpath="/data.fec.gov/can_sum/oth_com_con" regex="$|,|(.d{1,2})" replaceWith="" /> <field column="candidate_contrib" xpath="/data.fec.gov/can_sum/can_con" regex="$|,|(.d{1,2})" replaceWith="" /> <field column="total_contrib" xpath="/data.fec.gov/can_sum/tot_con" regex="$|,|(.d{1,2})" replaceWith="" /> <field column="net_contrib" xpath="/data.fec.gov/can_sum/net_con" regex="$|,|(.d{1,2})" replaceWith="" /> <field column="candidate_loan" xpath="/data.fec.gov/can_sum/can_loa" regex="$|,|(.d{1,2})" replaceWith="" /> <field column="other_loan" xpath="/data.fec.gov/can_sum/oth_loa" regex="$|,|(.d{1,2})" replaceWith="" /> <field column="total_loan" xpath="/data.fec.gov/can_sum/tot_loa" regex="$|,|(.d{1,2})" replaceWith="" /> <field column="net_operating_expenditures" xpath="/data.fec.gov/can_sum/net_ope_exp" regex="$|,|(.d{1,2})" replaceWith="" /> <field column="report_date" xpath="/data.fec.gov/can_sum/cov_end_dat" dateTimeFormat="MM/dd/yy" /> </entity> </document> </dataConfig>
Hier sind ein paar wichtige Dinge zu beachten…
- Ich habe die etwas „knappen“ Feldnamen aus den Quelldaten genommen und sie ein wenig erweitert. Kernfelder haben einfache Namen, während Feldnamen, die auf „contrib“ enden, sich auf Beiträge und Feldnamen, die auf „loan“ enden, auf Darlehen beziehen.
- Der XPathEntityProcessor von DIH verwendet eine benutzerdefinierte XPath-Implementierung, die es ermöglicht, das Streaming großer XML-Datenquellen zu unterstützen, ohne ein komplettes DOM im Speicher zu erstellen. Der Nachteil ist, dass er nur eine kleine Teilmenge von XPath unterstützt. Daher auch die etwas ausführlichen Ausdrücke.
- DIH verfügt über einen NumberFormatTransformer, der für das Parsen von Währungen nützlich sein kann, aber das Java NumberFormat für en-US Currency hat einige merkwürdige Vorstellungen von negativen Werten, so dass wir stattdessen eine einfache Regex verwenden. (Dies macht es uns auch leicht, Pfennige zu ignorieren.)
Jetzt, da wir eine DIH-Konfiguration haben, brauchen wir eine Instanz von Solr, um sie zu verwenden. Wir beginnen mit den Beispielkonfigurationen aus Solr 1.4 und bearbeiten die Felder in unserer schema.xml, damit sie mit den Feldern in den Daten übereinstimmen, an denen wir interessiert sind…
<fields> <field name="id" type="string" multiValued="false" /> <field name="name" type="text" multiValued="false" /> <field name="url" type="string" indexed="false" multiValued="false" /> <field name="report_date" type="date" multiValued="false" /> <field name="net_operating_expenditures" type="long" multiValued="false" /> <dynamicField name="*_loan" type="long" multiValued="false" /> <dynamicField name="*_contrib" type="long" multiValued="false" /> <dynamicField name="*" type="string" multiValued="false" /> </fields> <uniqueKey>id</uniqueKey> <defaultSearchField>name</defaultSearchField>
Beachten Sie, dass wir dynamicFields verwenden, um alle *_loan- und *_contrib-Felder zu definieren, um Zeit zu sparen, anstatt sie alle aufzulisten – ein praktischer Nebeneffekt der Wahl eines einfachen Feldbenennungssystems.
Wir nehmen auch einige Änderungen an unserer Datei solrconfig.xml vor…
<requestHandler name="/load" > <lst name="defaults"> <str name="config">fec-data-config.xml</str> <str name="indent">true</str> </lst> </requestHandler> <requestHandler name="standard" default="true"> <lst name="defaults"> <str name="echoParams">none</str> <str name="q">*:*</str> <int name="rows">0</int> <bool name="stats">true</bool> </lst> </requestHandler>
Der erste Abschnitt erstellt eine Instanz des DIH, die unsere Datei fec-data-config.xml kennt. Der zweite Abschnitt ist der Standard SearchHandler mit einigen Änderungen an seinem Standardverhalten:
- Suche nach allen Dokumenten: q=*:*
- Aktivieren Sie die Statistik: stats=true
- Blenden Sie die übereinstimmenden Zeilen aus: rows=0 (dies dient nur der Bequemlichkeit, da wir hauptsächlich an den Statistiken interessiert sind und uns die übereinstimmenden Zeilen oft nicht interessieren.
Damit starten wir Solr, weisen DIH an, einen „vollständigen Import“ durchzuführen, und überwachen, wann dieser abgeschlossen ist (d.h. im Leerlauf)…
$ curl -sS "http://localhost:8983/solr/load?command=full-import" > /dev/null $ curl -sS "http://localhost:8983/solr/load" | grep status <int name="status">0</int> <str name="status">busy</str> <lst name="statusMessages"> $ curl -sS "http://localhost:8983/solr/load" | grep status <int name="status">0</int> <str name="status">idle</str> <lst name="statusMessages">
Ungefähr 8 Sekunden später (hauptsächlich aufgrund der Verzögerung durch den FEC-Webserver) haben wir unsere Daten und können mit einigen Abfragen beginnen. Auch ohne die StatsComponent zu verwenden, können wir mit einer einfachen Suche/Sortierung bereits einige interessante Fakten aus diesen Daten lernen:
- Der Kandidat mit den höchsten Netto-Betriebsausgaben (14.404.986 $) ist die Senatskampagne für Harry Reid (D) in Nevada:
/solr/select?rows=1&sort=net_operating_expenditures+desc
- Die Senatskandidatin, die die meisten Kredite (14.000.000 $) für ihre Kampagne erhalten hat, ist Linda McMahon (R) in South Carolina:
/solr/select?q=office:S&rows=1&sort=total_loan+desc
- Der texanische Kandidat für das Repräsentantenhaus, der die höchsten Gesamtspenden (1.983.946 $) gemeldet hat, ist Chet Edwards (D) im Bezirk #17:
/solr/select?q=%2Boffice:H+%2Bstate:TX&rows=1&sort=total_contrib+desc
Ich weiß, was Sie jetzt denken: „Das sind nur einfache Abfragen der Rohdaten – wo sind die Statistiken?“ Also, hier ist es….
/solr/select?stats.field=total_contrib&stats.facet=office&stats.facet=party
Mit dieser einzigen URL fragen wir nach drei sehr aussagekräftigen Informationen und erhalten in etwa 45 ms eine Antwort zurück….
stats.field=total_contrib
– Damit wird Solr angewiesen, eine Reihe grundlegender Statistiken unter Verwendung des Feldes total_contrib aller Dokumente zu berechnen, die unserer Abfrage entsprechen (das sind im Moment alle Dokumente in unserem Index). Dieser einfache Parameter liefert uns die folgenden Informationen:<result name="response" numFound="2783" start="0"/> ... <double name="min">15.0</double> <double name="max">1.5645053E7</double> <double name="sum">7.35762149E8</double> <long name="count">1619</long> <long name="missing">1164</long> <double name="sumOfSquares">2.038433485484829E15</double> <double name="mean">454454.6936380482</double> <double name="stddev">1026250.909483362</double>
Wir können also sehen, dass von den 2783 Kampagnen, für die wir Daten haben, 1619 über ihre Gesamtbeiträge berichtet haben. Davon hat der Kandidat mit den geringsten Gesamtbeiträgen nur 15 $ erhalten, während der Kandidat mit den höchsten Gesamtbeiträgen 15.645.053 $ erhalten hat. Die Gesamtsumme aller von allen Kandidaten gemeldeten Spenden beläuft sich auf 735.762.149 $ – und es ist erst Mai!
stats.facet=office
– Mit diesem Parameter teilen wir der StatsComponent mit, dass wir zusätzlich zu den oben aufgeführten „Hauptstatistiken“ auch Statistiken für jede „Facette“ des Amtsbereichs sehen möchten:Wenn wir die Statistiken der Senatskampagnen mit denen des Repräsentantenhauses vergleichen, können wir sehen, dass die Senatskandidaten im „Durchschnitt“ etwa das Vierfache dessen erhalten, was die Kandidaten des Repräsentantenhauses bekommen (1.296.275 $ gegenüber 328.988 $). $328.988), obwohl die Gesamtsumme aller Spenden für die Kampagnen des Repräsentantenhauses etwa doppelt so hoch ist wie die aller Kampagnen des Senats ($463.544.421 gegenüber $272.217.728).stats.facet=party
– Damit wird Solr mitgeteilt, dass es parallel zu den anderen Statistiken, die wir bereits gesehen haben, auch die Statistiken für das Feld „Partei“ aufschlüsseln soll. Auf diese Weise können wir die Gesamtspenden nach der politischen Zugehörigkeit der Kandidaten vergleichen:<lst name="IND"> <double name="min">90.0</double> <double name="max">31845.0</double> <double name="sum">219388.0</double> <long name="count">32</long> <long name="missing">94</long> <double name="sumOfSquares">4.021803544E9</double> <double name="mean">6855.875</double> <double name="stddev">9012.011410406132</double> </lst> ... <lst name="DEM"> <double name="min">18.0</double> <double name="max">1.2442579E7</double> <double name="sum">3.84472068E8</double> <long name="count">574</long> <long name="missing">279</long> <double name="sumOfSquares">1.08397412569238E15</double> <double name="mean">669811.9651567944</double> <double name="stddev">1200966.840203952</double> </lst> ... <lst name="REP"> <double name="min">15.0</double> <double name="max">1.5645053E7</double> <double name="sum">3.49445424E8</double> <long name="count">974</long> <long name="missing">542</long> <double name="sumOfSquares">9.53132479905344E14</double> <double name="mean">358773.5359342916</double> <double name="stddev">922350.4925797922</double> </lst>
Hier sehen wir, dass die durchschnittlichen Gesamtspenden der demokratischen Kandidaten etwa doppelt so hoch sind wie die der Republikaner und zehnmal so hoch wie die der Unabhängigen ($669.811 vs. $358.773 vs. $6.855).
Alle diese Statistiken wurden bisher für den gesamten Index berechnet – aber wir können auch den Umfang eingrenzen, um die Statistiken nur für bestimmte Dokumente zu analysieren….
- Aufgeschlüsselte Einzelspenden an demokratische und republikanische Senatskandidaten:
/solr/select?q=%2Bparty%3A(DEM+REP)+%2Boffice%3AS&stats.facet=party&stats.field=itemized_individual_contrib
<lst name="REP"> <double name="min">15.0</double> <double name="max">9543057.0</double> <double name="sum">9.2695335E7</double> <long name="count">127</long> <long name="missing">74</long> <double name="sumOfSquares">3.40761264537769E14</double> <double name="mean">729884.5275590551</double> <double name="stddev">1472241.498436037</double> </lst> <lst name="DEM"> <double name="min">24.0</double> <double name="max">1.0200223E7</double> <double name="sum">1.01949939E8</double> <long name="count">69</long> <long name="missing">63</long> <double name="sumOfSquares">4.58668696973531E14</double> <double name="mean">1477535.347826087</double> <double name="stddev">2128359.138730218</double> </lst>
- Netto-Betriebsausgaben für demokratische Kandidaten für das Repräsentantenhaus, aufgeschlüsselt nach Bundesstaaten:
/solr/select?q=%2Bparty%3ADEM+%2Boffice%3AH&stats.facet=state&stats.field=net_operating_expenditures
... <lst name="MI"> <double name="min">585.0</double> <double name="max">761487.0</double> <double name="sum">3046606.0</double> <long name="count">18</long> <long name="missing">4</long> <double name="sumOfSquares">1.32730625872E12</double> <double name="mean">169255.88888888888</double> <double name="stddev">218504.30768344642</double> </lst> ... <lst name="MA"> <double name="min">1130.0</double> <double name="max">839985.0</double> <double name="sum">3454586.0</double> <long name="count">11</long> <long name="missing">3</long> <double name="sumOfSquares">1.650605122526E12</double> <double name="mean">314053.2727272727</double> <double name="stddev">237840.5102811928</double> </lst> ... <lst name="IL"> <double name="min">2981.0</double> <double name="max">1206092.0</double> <double name="sum">1.1289099E7</double> <long name="count">39</long> <long name="missing">16</long> <double name="sumOfSquares">6.798080371243E12</double> <double name="mean">289464.07692307694</double> <double name="stddev">304798.9738687473</double> </lst> ...
Diese Statistiken sind alle relativ simpel – und in Wahrheit wären sie in vielen anderen Tools einfacher zu berechnen. Das Wichtigste, was ich den Nutzern mit auf den Weg geben möchte, ist, dass Solr diese Art von Statistiken für jedes Suchergebnis schnell und einfach erstellen kann, wenn Ihre Daten bereits in Solr für die Suche vorhanden sind.