InstaLOC + Openstreetmap = Zusammenlegung und Erweiterung der Analyseoptionen

Durch die Zusammenführung beider Datenbanken wird eine wechselseitige Analyse auf Basis von

CREATE TABLE locations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
lat STRING,
long STRING,
name STRING,
osm_type STRING,
house_number STRING,
road STRING,
city STRING,
county STRING,
state_district STRING,
state STRING,
postcode STRING,
country STRING,
country_code STRING,
suburb STRING,
building STRING,
ruins STRING,
city_district STRING,
commercial STRING,
museum STRING,
library STRING,
aerodome STRING,
raceway STRING,
hamlet STRING,
hotel STRING,
clothes STRING,
parking STRING,
theatre STRING,
restaurant STRING,
footway STRING,
residental STRING,
supermarket STRING,
attraction STRING,
memorial STRING,
school STRING,
mall STRING,
beach STRING,
place_of_worship STRING,
hairdresser STRING,
stadium STRING,
bank STRING,
viewpoint STRING,
neigbourhood STRING,
university STRING,
car STRING,
zoo STRING,
fuel STRING,
bakery STRING,
bar STRING,
bus_stop STRING,
artwork STRING,
guest_house STRING,
village STRING,
cycleway STRING,
industrial STRING,
town STRING,
retail STRING,
wood STRING,
adress29 STRING,
residential STRING,
locality STRING,
garden STRING,
track STRING,
fast_food STRING,
pharmacy STRING,
picnic_site STRING,
castle STRING,
water STRING,
theme_park STRING,
golf_course STRING,
fort STRING,
car_wash STRING,
chemist STRING,
pedestrian STRING,
books STRING,
clinic STRING,
playground STRING,
community_centre STRING,
travel_agency STRING,
swimming_pool STRING,
sports_centre STRING,
hospital STRING,
florist STRING,
public_building STRING,
arts_centre STRING,
town_hall STRING,
cafe STRING,
pub STRING,
car_rental STRING,
fire_station STRING,
college STRING,
information STRING,
construction STRING,
viewpoint STRING
);

erlaubt. Themenwelten und Zielgruppen lassen sich nun auf Basis von hinterlegten Hotels, Straßen, PLZ, Stadtteilen oder auch Restaurants anstellen.

Projekt InstaLOC, aktueller Datenbestand (Stand: 27.11.2018)

Heute wurde ein Update der InstaLOC-Systeme veranlasst. Die Hauptdatendatei umfasst nun ~40GB mit folgenden Grundzahlen:

(1) Unique Beiträge: 64.000.547
(2) Unique (codierte) Usernames: 14.980.773
(3) Unique Locations: 2.096.459 (vorher: 1.7 Mio)

Eine Besonderheit wird hier von den Tagwolken eingenommen. Diese sind mit der aktuellen Abfragelogik nicht mehr als „Distinct“ in einer annehmbaren Geschwindigkeit auslesbar. Sehr wahrscheinlich werde ich einen Berechnungsdurchlauf in der kommenden Nacht durchführen lassen.

Das Projekt wurde, nach Rückmeldung(en) der vielen Geschäftsfreund_innen und Kund_innen, umkonzeptioniert, so dass externe Datenquellen angedockt werden können. Hier wurde ein spezielles Problem (final) gelöst, welches so beschrieben werden kann:

Die konkrete Bestimmung von Städten auf Basis der Instagramlocationangaben ist teilweise fehlerhaft / nicht möglich.
Die konkrete Bestimmung von Stadtteilen und deren Vergleichbarkeiten innerhalb EINER Stadt ist auf Basis der Instagramlocationangaben nur eingeschränkt möglich.

Die Ausgangslage wurde nun so entschärft:

(a) Export der Locationdaten in Form einer Distinct-Anweisung.
(b) Extrakt der Angaben „lat“, „long“ und „name“ aus dem Datenexport via for-to-do-schleife.
(c) Übergabe von „lat“ und „long“ an die Openstreetmap-API, Extrakt der Resultate und Speichern in eine neue Datenbankdatei.

Für die nachfolgenden Beispiele gilt:
„The Database made available under the Open Database License: http://opendatacommons.org/licenses/odbl/1.0/. Any rights in individual contents of the database are licensed under the Database Contents License: http://opendatacommons.org/licenses/dbcl/1.0/

Der Datenbestand umfasst (jeweils unique):
164.222 Eintragungen / 1.7 Mio
24.185 Stadtteile
221 Länder zu 203 Ländercodes
1630 States (Bundesländer etc.)
1131 State Districts (Bezirke etc.)
9715 County (Gemeinden, Regionen etc.)

Download Beispieldaten, Überblick (PDF)
Länder+Ländercodes
Länder+Ländercode+Aufzählung-Städte/a>
Berlin+Stadtteil+PLZ
Srilanka+Stadt+Stadtteil+PLZ
China+Stadt+Stadtteil+PLZ
Indien+Stadt+Stadtteil+PLZ
BRD+Stadt+Stadtteil+PLZ
USA+Stadt+Stadtteil+PLZ

Da die Abgleichsprozedur noch aktiv geschaltet ist, werden sich die Werte mit sehr hoher Wahrscheinlichkeit verändern. Interessant ist hier die zukünftige Beobachtung der TOP-Länder aus der 2. Beispieldatei.

Die verbleibenden 1.5 Mio Eintragungen werden „sehr wahrscheinlich“ in den nächsten 1 1/2 Wochen komplett abgearbeitet und mit Finalisierung wird das Recherchekonzept um einen weiteren Prüfpunkt erweitert. Folgende Szenarien sind dann „denkbar“

(a) Gezielte Analyse von Stadtteilen auf:
-> Zielgruppen
-> Trends via Kombination aus Tags, Tagwolken, Summe Likes + Comments, Zeitstempel
(b) Vergleich von Stadtteilen
(c) Vergleich von Städten auch auf Stadtteilebene
(d) Querprüfung auf Städte, Länder, Stadtteile etc. bzgl. der generellen Aktivitäten im Medium „Instagram“

Weitere Ideen, Anregungen oder Lust auf Austausch? Gern unter den bekannten Telefonnummern und office(at)pontipix.de

Datenauszugsfreigabe „InstaLOC“ (Stand: 12.11.2018)

Download: http://pontimania.de/_dbdownload/testauszuege.zip

Inhalt sind 3 Exceltabellen:
(a) Testdaten nach der Tagsuche „Urlaub“
(b) Testdaten nach der Locationsuche „Bayern“
(c) Testdaten nach der Locationsuche „Germany“.

Die Tabellen (b) und (c) beziehen sich auf Substrings, welche in der Spalte „Location“ befinden und die Beispieldatensätze haben ein festgelegtes (!) Limit i.H.v. 50.000 Zeilen. Die Dateien haben die Inhalte: Tags, Anzahl Likes + Comments, Locationangaben, Zeitstempel.

Je nach Abfrage und Projekt lassen sich folgende Fragen beantworten:

(a) Wieviele User schreiben in welchem Zeitfenster über den Urlaub an welchen Orten?
(b) Welche Orte werden an Hotspots von welchen Usergruppen besucht und was wird da geschrieben?
(c) Welche User / Usergruppen neigen zur Trendbildung an welchen Orten und / oder zu welchen Tags (Themen, Themenwelten)?
(d) Welche Orte werden zu welchen Zeitfenstern|Jahreszeiten|Monaten besonders stark frequentiert und was wird da geschrieben?
(e) An welchen Orten machen lokale Marketingkampagnen Sinn? (gemessen am Kommunikationsvolumen, Inhalte)
(f) Welche Emotionen werden mit Orten + Trends verbunden? (gemessen an Tags, Uservolumen, Sprachfarbe, Piktogramme und Fotofilter)
(g) Was wird mit Produkten vebrinden? (gemessen an Tags neben den Branchentags, Locations)
(h) Existiert eine Zielgruppe für mein Produkt? (gem. an Location, Tags, Taggestaltung, Zeitstempel)?
(i) Wo befindet sich meine Zielgruppe? (Query: Tag|Tagkombination auf Location)

Konkretere Antworten auf diese und weitere Fragen beantworte ich gern nach Projektsichtung und Teambesprechungen. Kontakt: office(at)pontipix.de oder via den üblichen Kanälen (siehe Impressum).

Statusupdate. InstaLOC: Zusammenführung und Bereinigung (Duplicate!) der Datenbanken

Heute wurde der vorhandene Datenbestand aus den einzelnen Dateien zusammengeführt und entsprechend gespeichert.
Der Befehl für den technischen Vorgang ist:

INSERT INTO instaloc_main.locations(url,tag,likes,comments,erstellzeit,post_id,username,location,filter,pruefzeit) select url,tag,likes,comments,erstellzeit,post_id,username,location,filter,pruefzeit FROM _main_10112018.locations group by url;

Die Datenbank hat folgende Daten

Speicher: ca 30GB

Analysierbar sind:
49.676.379 Beiträge
36.574.115 Tagwolken
12.705.076 (codierte) Nutzer
1.794.336 Loations
23.358.582 Zeitstempel

News: Zusammenlegung der Instagramprojekte

Per sofort wird der Support für das Projekt „Hashtag-DB“ / „Reichweitenanalysen v. Hashtags“ eingestellt und mit dem Themenkomplex „InstaLOC“ zusammen geführt.
Der Zugang zu den Datenbanken, generiert zwischen 2015/16 und 2018, ist für Externe ab dem heutigen Datum geschlossen.

Ausnahmen sind Geschäftspartner_innen und Kund_innen.

Link zum Archiv: https://www.pontipix.de/werkzeuge-tools/hashtag-projekt/

Themenweltendatenbank „Tourismus & Urlaub“: aktueller Bestand

Die Datenbank (SQLite-Datei) hat nun folgende Kennzahlen:

Speichervolumen: ~13GB
Beiträge (Unique): 18.411.849
Tagwolken (Unique): 17.490.694
(codierte) Nutzer_innen: 6.180.654
Locations (Unique): 1.037.477
Zeitstempel (Unique): 9.165.025

Mit Stand 27.10.2018 wurden 120.000 von 176721 Abfragen über die API innerhalb von ca 2 Wochen mit einem täglichen Scrapingzeitraum i.H.v. 11Stunden durchgeführt.

Ich rechne mit einem Abschluss der Themenwelten-Erfassungsfunktionen zum kommenden Mittwoch (31.10.2018) und im nächsten Turnus widme ich mit den Themen „Kunst“, „Kultur“, „Mode“, „Lifestyle“. Hier rechne ich mit ~300.000 Abfragen.

InstaLOC, Datenauszüge / Freigabe (Stand: 22.10.2018)

Folgende (Roh)datenauszüge beschreiben den Umfang der gesammelten Informationen.

(1) Die Locations
export_locs_22102018.rar

(2) Die Zeitstempel
times.rar

(3) Die Tagwolken
export_tags_22102018.rar

Bitte beachten.
Die Locationsdatei umfasst 3 Pakete: Auflistung, Zuordnung zu den gesammelten Likes und Zuordnung zu den gesammelten Comments.
Die Zeitstempeldatei umfasst ein Paket.
Die Tagwolkendatei umfasst 3 Pakete: Auflistung, Zuordnung zu den aktiven User_innen und Zuordnung zu den gesammelten Likes.

Die entpackten CSV-Daten schwanken zwischen wenigen 100MB bis zu 5GB und man muss über entsprechende Parser / Ressourcen verfügen, um die Daten interpretieren zu können. Hier gilt: Support wird ausschließlich den Kund_innen und den (Geschäfts)freund_innen geleistet.

InstaLOC, Datenbestand – Überblick

Nach Zusammenführung der fehlerbereinigten Datensätze (Duplikate etc.) in eine Master-DB mit den Inhalten:

-> Städte aus dem RolandBerger-Projekt
-> div. deutsche Groß- und Kleinstädte
-> politische Analyse
-> Themenwelt „Home & Living“
-> 1/3 – Datenbank aus Themenwelt „Tourismus“

kommen wir nun auf den folgenden Bestand:

24.321.643 Beiträge
19.123.483 Tagwolken
8.031.350 (codierte) Nutzer_innen
1.084.069 Locations
14.540.475 Zeitstempel

Die Datenbankdatei ist umfasst ca. 13GB und wird je Durchlauf um 3-5GB wachsen. Der aktualisierte Datenbestand wird zeitnah an die W&L GbR Partner_innen verteilt.

InstaLOC, Zwischenfreigabe der Themendatenbank „Tourismus“

Die aktuelle Datenbank umfasst die Ergebnisse aus 23575 Abfragen und speichert folgende Daten:

4.546.235 Beiträge
4.376.548 Tagwolken
2.031.490 codierte User
380.723 Locations
2.674.339 Zeitstempel

Datenauszüge (unverschlüsselt)

(1) Auflistung Tagwolken und deren Locations
Datei: exp_urlaub_tag_loc.zip
Dateivolumen: ZIP->339MB, Entpackt->1.6GB

(2) Auflistung der Locations und Aufsummierung der Likes JE Location
Datei: exp_urlaub_like_locs.zip
Dateivolumen: ZIP->13MB, Entpackt->42MB

(3) Auflistung Tagwolken (ungefiltert!) und deren Likes
Datei: exp_urlaub_tag_likes.zip
Dateivolumen: ZIP->168MB, Entpackt->600MB

(4) Auflistung der Locations + Postingzeitstempel + Likes
Datei: exp_urlaub_loc_time_likes.zip
Dateivolumen: ZIP->52MB, Entpackt->265MB

(5) Auflistung der Locations + Aufsummierung der Postings
Datei: exp_urlaub_postings_locs.zip
Dateivolumen: ZIP->12MB, Entpackt->42MB

(6) Auflistung der Tagwolken + Aufsummierung der User, welche die Wolken verwendeten
Datei: exp_urlaub_tags_user.zip
Dateivolumen: ZIP->333MB, Entpackt->1.5GB

(7) Auflistung der Locations + Aufsummierung der User, welche an den Locations aktiv waren
Datei: exp_urlaub_loc_user.zip
Dateivolumen: ZIP->13MB, Entpackt->41MB

Die aufgelisteten Datenauszüge geben einen ersten und sehr guten Überblick.
Im Bezug zu den erfassten Datensätzen sind weitere Nachforschungen die Beantwortung hochfaszinierender Fragen, wie:

(a) Wieviele User schreiben in welchem Zeitfenster über den Urlaub an welchen Orten?
(b) Welche Orte werden an Hotspots von welchen Usergruppen besucht und was wird da geschrieben?
(c) Welche User / Usergruppen neigen zur Trendbildung an welchen Orten und / oder zu welchen Tags (Themen, Themenwelten)?
(d) Welche Orte werden zu welchen Zeitfenstern|Jahreszeiten|Monaten besonders stark frequentiert und was wird da geschrieben?

möglich.

Die Anwendungsszenarien sind vielfältig. Ich denke an die folgenden Punkte:

-> Influenceraccountanalysen
-> Schnittstellen zu Socialmediastrategien inkl. Hashtag- und Postzeitplanungen
-> Schnittstellen zu div. Textanalysetools mit Anbindung an WDF*IDF / KWD-Analysen
-> gezielte Steuerung von ortsbezogenen Werbeanzeigen|Flyeraktionen|Plakataktionen|sonst.Promomaßnahmen
-> Gegenprobe auf die üblichen Auswertungstools aus der Socialmedia
-> gezielte Steuerung von ortsbezogenen Werbeanzeigen in den Suchmaschinen, den Socialmedia

Interesse am Austausch? Fragen? Anfragen?
Konkretes Projektangebot?
Ich freue mich auf Rückmeldung unter der eMail: office(at)pontipix.de

Projekt „InstaLOC“ – Update der Scrapertechnologie + Bugfixing

Während der letzten Datendurchläufe stellte ich immer wieder fest, dass der Scraper den Arbeitsspeicher zu stark beanspruchte. Konkret bedeutet das, dass ca. 250 Abfragen an die API einen Scrapingabbruch und einen RAM-Verbrauch i.H.v. 1,8GB (!) provozierte.

Dieses Problem wurde nun final über die Quellcodeanpassung
jsonvalue.Free;
JSON.Free;

gelöst.

Der Speicherverbrauch wurde von 1.8GB auf ca. 100MB / je 250 Abfragen reduziert.

Die fehlerbereinigte Prozedur ist:
procedure TForm1.getmedia_db(mytable: TStringGrid; tagsearch: string; rounds: integer);
var
JSONArray: tJSONArray;
JSONValue,jvalue: tJSONValue;
JSONPair: TJSONPair;
JSON, json_sub: TJSONObject;
size: integer;
j_array: tJSONArray;
s: string;
i,j: integer;
next_id: string;
zaehl: integer;
url,tag,likes,comments,post_id,username,location,filter,pruefzeit: widestring;
erstellzeit: string;
gedoens: TIdHTTP;
zw_db: tmemo;
begin
gedoens := TIdHTTP.Create;
zw_db :=tmemo.Create(self);
sql_befehle.Clear;
try
zw_db.text:=gedoens.Get('https://api.instagram.com/v1/tags/'+escape(tagsearch)+'/media/recent?access_token='+token.text);
JSONValue := TJSONObject.ParseJSONValue(zw_db.text);
JSON := TJSONObject.ParseJSONValue(zw_db.Lines.Text) as TJSONObject;
JSONArray := TJSONArray(JSON.Get('data').JsonValue);
try next_id:= JSONValue.GetValue('pagination.next_url');
except
//-> hier user, locations etc. einbauen!!!
next_id:='N/A';
end;

for i := 0 to JSONArray.Size - 1 do
begin
url:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('link')).JsonValue.Value);
s:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('tags')).ToString);
s:= StringReplace(s, '"tags":[', '', [rfReplaceAll,rfIgnoreCase]);
s:= StringReplace(s, ']', '', [rfReplaceAll,rfIgnoreCase]);
tag:=escape(s);
s:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('likes')).ToString);
s:= StringReplace(s, '"likes":{"count":', '', [rfReplaceAll,rfIgnoreCase]);
s:= StringReplace(s, '}', '', [rfReplaceAll,rfIgnoreCase]);
likes:=s;
s:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('comments')).ToString);
s:= StringReplace(s, '"comments":{"count":', '', [rfReplaceAll,rfIgnoreCase]);
s:= StringReplace(s, '}', '', [rfReplaceAll,rfIgnoreCase]);
comments:=s;
erstellzeit:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('created_time')).JsonValue.Value);
erstellzeit:=datetimetostr(UnixToDateTime(strtoint(erstellzeit)));
post_id:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('id')).JsonValue.Value);
s:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('user')).ToString);
s:= StringReplace(s, '"user":{"username":', '', [rfReplaceAll,rfIgnoreCase]);
s:= StringReplace(s, '}', '', [rfReplaceAll,rfIgnoreCase]);
s:= StringReplace(s, '"', '', [rfReplaceAll,rfIgnoreCase]);
username:=s;
s:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('location')).ToString);
s:= StringReplace(s, '"location":', '', [rfReplaceAll,rfIgnoreCase]);
location:=s;
filter:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('filter')).JsonValue.Value);
pruefzeit:=datetimetostr(now);
with sql_befehle.Lines do
begin
add('INSERT INTO `locations` (`url`, `tag`, `likes`, `comments`, `erstellzeit`, `post_id`, `username`, `location`, `filter`, `pruefzeit`) Values ('''+url+''', '''+tag+''', '''+likes+''', '''+comments+''', '''+erstellzeit+''', '''+post_id+''', '''+username+''', '''+location+''', '''+filter+''', '''+pruefzeit+''');');
end;
end;
fdquery3.ExecSQL(sql_befehle.text);
sql_befehle.Clear;
// sql_befehle.Free;
except
tr_break:='1';
end;

// -> Speicherfreigabe
jsonvalue.Free;
JSON.Free;
if next_id<>'N/A' then
begin
repeat
// -> tiefenpruefung
if next_id='N/A' then
break;
delay(strtoint(frequenz1.Text));
try
zw_db.text:=gedoens.Get(next_id);
JSONValue := TJSONObject.ParseJSONValue(zw_db.text);
JSON := TJSONObject.ParseJSONValue(zw_db.Lines.Text) as TJSONObject;
JSONArray := TJSONArray(JSON.Get('data').JsonValue);
try next_id:= JSONValue.GetValue('pagination.next_url');
except
next_id:='N/A';
break;
end;
for i := 0 to JSONArray.Size - 1 do
begin
url:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('link')).JsonValue.Value);
s:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('tags')).ToString);
s:= StringReplace(s, '"tags":[', '', [rfReplaceAll,rfIgnoreCase]);
s:= StringReplace(s, ']', '', [rfReplaceAll,rfIgnoreCase]);
tag:=escape(s);
s:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('likes')).ToString);
s:= StringReplace(s, '"likes":{"count":', '', [rfReplaceAll,rfIgnoreCase]);
s:= StringReplace(s, '}', '', [rfReplaceAll,rfIgnoreCase]);
likes:=s;
s:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('comments')).ToString);
s:= StringReplace(s, '"comments":{"count":', '', [rfReplaceAll,rfIgnoreCase]);
s:= StringReplace(s, '}', '', [rfReplaceAll,rfIgnoreCase]);
comments:=s;
erstellzeit:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('created_time')).JsonValue.Value);
erstellzeit:=datetimetostr(UnixToDateTime(strtoint(erstellzeit)));
post_id:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('id')).JsonValue.Value);
s:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('user')).ToString);
s:= StringReplace(s, '"user":{"username":', '', [rfReplaceAll,rfIgnoreCase]);
s:= StringReplace(s, '}', '', [rfReplaceAll,rfIgnoreCase]);
s:= StringReplace(s, '"', '', [rfReplaceAll,rfIgnoreCase]);
username:=s;
s:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('location')).ToString);
s:= StringReplace(s, '"location":', '', [rfReplaceAll,rfIgnoreCase]);
location:=s;
filter:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('filter')).JsonValue.Value);
pruefzeit:=datetimetostr(now);
with sql_befehle.Lines do
begin
add('INSERT INTO `locations` (`url`, `tag`, `likes`, `comments`, `erstellzeit`, `post_id`, `username`, `location`, `filter`, `pruefzeit`) Values ('''+url+''', '''+tag+''', '''+likes+''', '''+comments+''', '''+erstellzeit+''', '''+post_id+''', '''+username+''', '''+location+''', '''+filter+''', '''+pruefzeit+''');');
end;
end;
fdquery3.ExecSQL(sql_befehle.text);
sql_befehle.Clear;
except
tr_break:='1';
break;
end;
// -> Speicherfreigabe
jsonvalue.Free;
JSON.Free;
// -> tiefenpruefung, ende
zaehl:=zaehl+1;
until zaehl=rounds;
end;
form1.Caption:=version+' alle Posts herunter geladen';
gedoens.free;
zw_db.Free;
fdquery.Free;
end;