Datenträger unter Ubuntu bereinigen

Ich habe gerade eben folgende Fehlermeldung nach dem Start von Ubuntu bekommen:

Auf dem Datenträger „Wurzelordner des Dateisystems“ ist nur noch XXX kB Speicherplatz verfügbar.

In meinem Falle war XXX gleich 0. Es war also höchste Zeit, dass ich mal wieder unnötige Dateien von meiner System-Partition lösche. Ich hatte allerdings längst wieder vergessen, was man alles machen kann. Daher habe ich nun eine kleine Liste zusammengestellt:

  • Zunächst habe ich den Inhalt des temporären Verzeichnisses gelöscht.

    1
    2
    
    # Temporäreres Verzeichnis leeren
    rm -r /tmp/*

    Darin hatten sich Fehlermeldungen von apport angesammelt, die bei Programmabstürzen erstellt worden waren. Teilweise konnten diese aber nicht abgesendet werden, weil keine Internetverbindung bestand. In meinem Falle hatten sich über die Jahre mehr als 1.5 GB angesammelt.

  • Im Anschluss habe ich heruntergeladene Paket-Dateien, sowie nicht mehr benötigte Pakete gelöscht:

    1
    2
    3
    4
    
    # Paketdateien löschen
    sudo apt-get clean
    # Nicht mehr benötigte Pakete löschen
    sudo apt-get --purge autoremove

    Letzterer Befehl hat früher scheinbar auch nicht mehr benötigte Kernel-Versionen gelöscht (UbuntuUsers Forum). Das ist jetzt allerdings nicht mehr der Fall.

  • In regelmäßigen Abständen sollte man auch das Programm baobab („Festplattenbelegung analysieren“) aufrufen. Damit kann man herausfinden, welche Verzeichnisse besonders viele Daten enthalten. In meinem Falle habe ich gesehen, dass sich viele Kernel-Versionen angesammelt hatten (Ordner: /usr/src und /lib/modules):

    Das Programm "baobab" stellt die Größe von Ordnern grafisch dar. In diesem Fall kann man erkennen, dass ein großer Teil der Partition mit alten Kernel-Versionen belegt ist.
    Das Programm „baobab“ stellt die Größe von Ordnern grafisch dar. In diesem Fall kann man erkennen, dass ein großer Teil der Partition mit alten Kernel-Versionen belegt ist.

    Wie im UbuntuUsers-Forum beschrieben, kann man im Terminal ähnlich vorgehen:

    1
    2
    
    # Platzbedarf der Ordner im Wurzelverzeichnis anzeigen
    sudo du -h / --max-depth=1

    Im Anschluss kann man sich weiter auf die Suche machen und z.B. eine Liste der installierten Kernel-Versionen ausgeben lassen:

    1
    2
    
    # Installierte Kernel-Versionen anzeigen lassen
    dpkg -l linux-image-*

    Die Ausgabe könnte dann folgendermaßen aussehen:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    
     

    Da bei mir vor allem die Zahl der alten Linux-Kernel ein Problem war, habe ich einige davon gelöscht. Wie im Wiki von UbuntuUsers beschrieben, habe ich dazu in der Paketverwaltung Synaptic nach

    1. linux-image-
    2. linux-headers-

    gesucht und entsprechende Pakete vollständig entfernt. Mindestens eine ältere Version sollte man allerdings behalten. Dadurch habe ich 3.5GB frei machen können.

    Wenn man die Kernel im Terminal entfernen möchte, sind diverse Lösungen im Netz zu finden: LinuxMintUsers.de, webupd8.org, linuxundich.de, UbuntuUsers Forum

  • Große Dateien können sich auch im Verzeichnis /var/log ansammeln. Das war bei mir allerdings nicht der Fall, was ich folgenden Befehlen überprüft habe:

    # Dateien sortiert nach Nutzungsdatum auflisten
    ls -aluh /var/log
    # Größe des gesamten Ordners ausgeben lassen
    sudo du -sh /var/log
  • Wenn man im eigenen Home-Verzeichnis Ordnung schaffen möchte, bietet sich das Programm FSlint an. Nach der Installation des Programmpaketes fslint, lässt sich das Programm über den Befehl fslint-gui starten. Im Anschluss kann man viele ungenutzte Dateien und Ordner suchen und ggf. direkt löschen:

    • Duplikate
    • Temporäre Dateien (außerhalb des Verzeichnisses /tmp)
    • Leere Verzeichnisse
    • Fehlerhafte Symlinks
    Das Programm FSlint kann unter anderem Dateien mit identischem Inhalt finden. Dabei spielt es keine Rolle, ob die Dateien unterschiedliche Namen oder Erstellungsdaten haben.
    Das Programm FSlint kann unter anderem Dateien mit identischem Inhalt finden. Dabei spielt es keine Rolle, ob die Dateien unterschiedliche Namen oder Erstellungsdaten haben.

Die richtigen Tasten auf deutscher Tastatur bei englischer Tastaturbelegung finden

Der ein oder andere kennt das Problem: der Rechner funktioniert nicht, und man muss ins Wiederherstellungs-Terminal. Zu dem Zeitpunkt ist allerdings die korrekte Tastaturbelegung noch nicht geladen. Man hat zwar eine deutsche Tastatur angeschlossen, aber die gedrückten Tasten (deren Signale) werden so interpretiert, als handele es sich um eine englische Tastatur. Dann geht das suchen los, denn Passwörter und Terminal-Befehle wollen richtig eingegeben werden.

Die folgende kleine Liste enthält häufig benötigte Zeichen, sowie die Taste oder Tastenkombination, die dazu auf einer deutschen Tastatur gedrückt werden muss.

Gewünschtes Zeichen Taste / Tastenkombintation
* ⇧ Shift + 8
| ⇧ Shift + #
@ ⇧ Shift + 2
?
/
y z
z y
= ´

Eine Liste zu einem data.frame konvertieren in R

Manchmal liegen in R Daten in Form einer Liste vor (z.B. die Ausgabe der Funktion hist()). In einer Liste können Daten enthalten sein, die eine unterschiedliche Länge haben. Im Falle von hist() sind z.B. Arrays unterschiedlicher Länge gemeinsam mit einfachen Variablen in einer Liste kombiniert.

Für weitere Analysen kann es jedeoch hilfreich sein, die gleich langen Teile in einen separaten data.frame auszulagern. Dann kann z.B. mit Hilfe der Funktion subset() relativ einfach Bereiche aus den Daten herausfiltern.

In R gibt es keine vorgefertigte Funktion, die direkt Daten vom Typ list in Daten vom Typ data.frame konvertieren kann. Das liegt daran, dass in einem data.frame alle enthaltenen Variablen (in der Regel Arrays) die gleiche Länge haben müssen. Unsere Entscheidung, welche Variablen aus der Liste in den data.frame übernommen werden sollen, müssen wir R mitteilen.

Das folgende Beispiel zeigt, wie man das sehr einfach bewerkstelligen kann:

1
2
3
4
5
6
7
8
# Liste mit Arrays ("x", "y", "sd") und einer Variablen ("name")
liste = list(x=c(1:5), y=c(11:15), sd=c(0,1,2,0,0), name="Meine Liste")
 
# data.frame ("df") erzeugen mit den Variablen "x", "y" und "sd"
df = with(data=liste, expr=data.frame(x, y))
 
# Struktur des data.frames ausgeben
str(df)
'data.frame':	5 obs. of  3 variables:
 $ x : int  1 2 3 4 5
 $ y : int  11 12 13 14 15
 $ sd: num  0 1 2 0 0

Im Anschluss kann man sehr einfach nur bestimmte Teile des data.frame ausgeben lassen.
Das kann man z.B. direkt über den Index (df[zeile, spalte]) oder über die Funktion subset() machen.

1
2
3
4
5
6
7
8
9
# Nur das zweite und vierte Element (Zeile) anzeigen
df[c(2,4),]
 
# Nur die Elemente (Zeilen) anzeigen, bei denen x>2 ist
df[(df$x>2),]
 
# Nur die Elemente (Zeilen) der Variablen (Spalten) x und y ausgeben,
# bei denen sd<1 und x>2 ist
subset(df, subset=(x>2 & sd<1), select=c(x,y))

Klassifizierung von Messwerten in R

Stell Dir vor, Du hast die Länge von 1000 Fischen gemessen. Im Anschluss möchtest Du die eine Häufigkeitsverteilung (Histogramm) der Größen erstellen. Je nachdem wie genau du gemessen hast, wirst du keine zwei Fische mit der gleichen Länge finden. Daher bist Du gut beraten, die Daten zunächst in bestimmte Längenklassen einzuteilen (z.B. „Anzahl von Fischen zwischen 23cm und 24cm“). Für diese Klassifizierung (binning) steht Dir in R die Funktion hist() zur Verfügung.

Nehmen wir mal an, die Längen der Fische folgen einer Normalverteilung. Im Durschnitt haben die Fische eine Länge von 25cm (± 5cm)

1
2
3
# Ziehe Eintausend Zufallszahlen aus einer Normalverteilung
# (Mittelwert: 25; Standardabweichung: 5)
laengen = rnorm(n=1e3, mean=25, sd=5)

Mit der Funktion hist() kannst Du die Daten nun in Klassen einteilen und plotten lassen.

1
2
3
# Klassifiziere die Daten
# (=Erstelle eine Histogramm und stelle es dar)
gebinnt = hist(laengen, plot=TRUE)
Automatisch erstelltes Histogramm der Beispieldaten. Die Klassengrenzen wurden von R bestimmt.
Automatisch erstelltes Histogramm der Beispieldaten. Die Klassengrenzen wurden von R bestimmt.

hist() erstellt nun eine list, in der die Klassengrenzen (breaks), die Häufigkeiten (counts), Dichten (densitiy) und Klassenmitten (mids), sowie der Name der ursprünglichen Variable (xname) und die Information, ob die Klassen alle gleich groß sind (equidist), gespeichert werden:

1
str(gebinnt)
List of 7
 $ breaks     : num [1:9] 5 10 15 20 25 30 35 40 45
 $ counts     : int [1:8] 3 29 140 370 312 129 15 2
 $ intensities: num [1:8] 0.0006 0.0058 0.028 0.074 0.0624 0.0258 0.003 0.0004
 $ density    : num [1:8] 0.0006 0.0058 0.028 0.074 0.0624 0.0258 0.003 0.0004
 $ mids       : num [1:8] 7.5 12.5 17.5 22.5 27.5 32.5 37.5 42.5
 $ xname      : chr "laengen"
 $ equidist   : logi TRUE
 - attr(*, "class")= chr "histogram"

Für weitere Analysen kannst Du selbst noch die Breite der Klassen (breite) und den Anteil der Klassen an der Stichprobe (anteil) zur Liste hinzufügen:

1
2
gebinnt$breite = diff(gebinnt$breaks)
gebinnt$anteil = gebinnt$counts / sum(gebinnt$counts)

Eigene Klassenbreiten festlegen

Du hast natürlich auch die Möglichkeit, selbst Klassengrenzen (breaks) anzugeben. Die Klassen müssen auch nicht alle gleich Groß sein. Bei einigen Daten können z.B. logarithmische Bin-Größen sinnvoll sein.

1
2
3
4
# Klassen mit Klassenbreite 1 (cm) erstellen
gebinnt = hist(
  laengen, plot=T, breaks=c(0:50)
  , xlab="Länge (cm)", ylab="Häufigkeit", main="Häufigkeitsverteilung")
Histogramm mit selbst gewählten Klassengrenzen (hier: Klassenbreite=1cm)
Histogramm mit selbst gewählten Klassengrenzen (hier: Klassenbreite=1cm)

Hierbei muss man allerdings darauf achten, dass keiner der Werte ausgeschlossen wurde, weil er ausserhalb der gewählten Klassen lag bzw. auf die untere (oder obere) Klassengrenze gefallen ist.

Fehler in hist.default(laengen, plot = T, breaks = c(15:50), xlab = "Länge (cm)",  : 
  einige 'x' nicht gezählt: evtl. überdecken die 'breaks' nicht den gesamten Bereich von 'x'

Daher sollte man immer prüfen, ob die Summe der Werte in den Klassen auch tatsächlich der Stichprobengröße entspricht.

# Sind alle Messwerte der Stichpobe im Histogramm berücksichtigt?
sum(gebinnt$counts)

Eventuell muss man dann weitere Klasse hinzunehmen, bzw. die untere (oder obere) Klassengrenze zu einer Klasse hinzu zählen (Option include.lowest=T).

Alternativen

Alternativ zur Funktion hist() könnte man ein Histogramm auch durch die Anwendung der Funktion table() auf gerundete Daten (round()) erstellen: table(round(daten)).

Die Funktion table() ist dazu gedacht die „Anzahl gleicher Werte zu ermitteln“. Das entspricht aber nicht ganz dem Gedanken der Klassifizierung.

Fehlerbalken in R-Grafik einzeichnen

In wissenschaftlichen Publikationen werden häufig Messwerte in Grafiken dargestellt. Messungen sind allerdings immer fehlerbehaftet. Daher sollte man dem Leser mitteilen, wie verlässlich die gemessenen Werte sind. In der deskriptiven Statistik gibt es dafür diverse Kennzahlen, wie z.B. die Standardabweichung oder den Standardfehler. Diese werden oft als Fehlerbalken in die Grafiken eingefügt.

errorbars
Grafisch dargestellte Messwerte mit Fehlerbalken.

In R gibt es leider keine Standardmethode, die diese Aufgabe übernimmt. Zunächst hatte ich nach Anleitungen im Internet eigene Funktionen für diese Aufgabe erstellt.

  • Eine Lösung fand ich bei Stackoverflow. Allerdings wurden hier die horizontalen Linien bei einer logarithmischen X-Achse nicht korrekt angezeigt (links und rechts waren die Linien unterschiedlich lang).
  • Die Lösung von MonkeysUncle war in der Hinsicht besser. Allerdings wurde keine horizontale Linie angezeigt, wenn der Fehler 0 war. Zudem wurde gar kein Fehlerbalken angezeigt, wenn die untere Grenze des Fehlers (bei logarithmischer Y-Achse) im negativen Bereich lag.

Schließlich habe ich die Funktion errbar() im Paket Hmisc gefunden (siehe auch StackOverflow). Hier werden:

  1. Die horizontalen Linien auch bei logarithmischer X-Achse korrekt gezeichnet.
  2. Bei logarithmischer Y-Achse und negativer unteren Fehlergrenze, wird zumindest die obere Fehlergrenze geplottet.
  3. Eine horizontale Linie wird auch hinzugefügt, wenn der Fehler 0 ist.
  4. Die Y-Ranges werden automatisch gewählt, wenn die Fehlerbalken ausserhalb der Grafik liegen würden.

Das folgende Beispiel zeigt, wie man Datenpunkte mit ihren Fehlerbalken in eine Grafik einträgt.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Datenpunkte (x, y) mit einer Standardabweichung (sd)
daten = data.frame(
  x  = c(1:5)
  , y  = c(1.1, 1.5, 2.9, 3.8, 5.2)
  , sd = c(0.2, 0.3, 0.2, 0.0, 0.4)
)
 
# Paket "Hmisc" installieren und laden 
install.packages("Hmisc", dependencies=T)
library("Hmisc")
 
# Plot mit automatischer Wahl des Y ranges
with (
  data = daten
  , expr = Hmisc::errbar(x, y, y+sd, y-sd, pch=1)
)
 
# Datenpunkte mit Fehlerbalken zu einem
# existierenden Koordinatensystem hinzufügen (add=T)
plot(daten$x, daten$y, type="n", xlab="X-Werte", ylab="Y-Werte")
with (
  data = daten
  , expr = Hmisc::errbar(x, y, y+sd, y-sd, pch=2, add=T)
)

Die Funktion errbar() erweitert die Funktion plot(). Daher können die Grafikparameter von plot() und par() (hier z.B. pch) verwendet werden. Zusätzlich gibt es noch Parameter, mit denen sich z.B. die breite der horizontalen Begrenzung (cap) steuern lässt.

Funktion aus einem bestimmten R-Paket laden

Die Programmiersprache R kann durch Funktionen erweitert werden, die von anderen Nutzern erstellt wurden. Oftmals sind diese Erweiterungen in Paketen zusammengefasst. Ein Problem tritt allerdings dann auf, wenn in unterschiedlichen Paketen Funktionen enthalten sind, die den gleichen Namen tragen (siehe: Stackoverflow).

Ich nutze z.B. folgende Pakete sehr häufig:

  • sfsmisc – Mit der Funktion eaxis() lassen sich schöne logarithmische Achsen erstellen. Die Beschriftung wird dabei von der Funktion pretty10exp() übernommen.
  • Hmisc– Mit der Funktion errbar() lassen sich sehr leicht Fehlerbalken in Plots eintragen.
  • TeachingDemos – Mit der Funktion subplot() lassen sich sehr einfach Insets zu Plots hinzufügen.

Lädt man allerdings die Pakete,

## Installation der Pakete
install.packages("sfsmisc", dependencies=T)
install.packages("Hmisc", dependencies=T)
install.packages("TeachingDemos", dependencies=T)
 
## Laden der Pakete
library(package = "sfsmisc")
library(package = "Hmisc")
library(package = "TeachingDemos")

dann erhält man folgende Fehlermeldungen:

Attache Paket: ‘Hmisc’

Das folgende Objekt ist maskiert from ‘package:survival’:
    untangle.specials

Das folgende Objekt ist maskiert from ‘package:sfsmisc’:
    errbar

Das folgende Objekt ist maskiert from ‘package:base’:
    format.pval, round.POSIXt, trunc.POSIXt, units

Man kann erkennen, dass sowohl Hmisc als auch sfsmisc eine Funktion namens errbar() enthalten.

Attache Paket: ‘TeachingDemos’

Das folgende Objekt ist maskiert from ‘package:Hmisc’:
    cnvrt.coords, subplot

Man kann erkennen, dass sowohl TeachingDemos als auch Hmisc eine Funktion mit Namen subplot() enthalten.

Um nun die Funktion aus einem bestimmten Paket zu verwenden, kann man R dies mit Hilfe von zwei Doppelpunkten :: mitteilen:

# Verwende die Funktion subplot() aus dem Paket TeachingDemos
TeachingDemos::subplot(...)
 
# Verwende die Funktion errbar() aus dem Paket Hmisc
Hmisc::errbar(...)

Meine Empfehlung: Wenn man Funktionen aus einem Paket verwendet, sollte man beim Aufruf der Funktion immer diese Notation verwenden. Zum einen hilft es dem Leser zu erkennen, woher diese Funktion stammt. Zum anderen verhindert man unnötige Verwirrung, wenn man zu einem späteren Zeitpunkt Pakete einbindet, die Funktionen mit gleichem Namen enthalten.

Webseite komplett herunterladen

Informationen im Internet sind kurzlebig und können nur abgerufen werden, sofern ein Internet-Anschluss verfügbar ist. Problematisch wird es also, wenn Websites gelöscht werden, oder man gerade keinen Zugriff auf das Internet hat (z.B. auf Reisen).

Gelöschte oder ältere Versionen von Websites findet man in Internet Archiven wie der WayBackMachine. Man kann sich die Webseiten allerdings auch selbst zum offline lesen herunterladen.

Ein beliebtes Programm dafür ist wget:

wget -r -k -E -l 8 http://de.wikipedia.org

Mit diesem Befehl würde man die deutsche Version der Wikipedia herunterladen. Die verwendeten Optionen haben folgende Bedeutungen:

-r Websites zum Herunterladen rekursiv durchlaufen.
-l 8 Bei der Rekursion maximal 8 Ebenen („Ordner“) tief vordringen (Standard ist 5)
-k Konvertiere Links, damit sie lokal funktionieren.
-E Erzwinge die Dateiendung „.html“; Das ist besonders dann nützlich, wenn man „.php“ oder „.asp“-Dateien herunterlädt.

Weietere Optionen und Informationen findest Du im Wiki von UbuntuUsers.

Falls Du diesen Befehl häufiger verwenden, Du Dir aber die ganzen Optionen nicht merken möchtest, kannst Du Dir einen Alias anlegen. Solltest Du die bash als Standard-Terminal (Shell) verwenden, musst Du dazu lediglich folgende Zeile in die Datei .bashrc in Deinem Home-Verzeichnis eintragen:

alias wdown='wget -r -k -E -l 8'

Im Anschluss steht Dir der Terminal-Befehl wdown zur Verfügung und Du könntest Dir die deutsche Wikipedia folgendermaßen herunterladen:

wdown http://de.wikipedia.org

Bevor Du allerdings Seite herunterlädst, solltest Du Dich mit den Urheberrechten auseinander setzen.

Plot-Funktion in R erweitern

Manchmal möchte man eine bestehende Funktion in der Programmiersprache R um einen eigenen Parameter erweitern. Die Parameter der Ausgangsfunktion sollen dabei einfach übernommen werden, ohne sie innerhalb der eigenen Funktion definieren und einzeln übergeben zu müssen. Die Weiterleitung von Parametern kann in R durch ... realisiert werden.

Im folgenden Beispiel erweitere ich die R-Funktion plot(). In der neuen Funktion plot.mein() kann zusätzlich eine rote horizontale und/oder vertikale Linie eingezeichnet werden.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Definition der neuen Funktion
plot.mein <- function(..., hline=NULL, vline=NULL) {
  # Plote die Daten
  # Leite die Grafik-Parameter direkt an die Funktion plot() weiter
  plot(...)
 
  # Füge eventuell eine horizontale rote Linie hinzu
  if(!is.null(hline)) {
    abline(h=hline, col="#ff0000")
  }
 
  # Füge eventuell eine vertikale rote Linie hinzu
  if(!is.null(vline)) {
    abline(v=vline, col="#ff0000")
  }
}
# Die Parameter x, y und type werden direkt an die Funktion plot weitergeleitet
plot.mein(c(1:6), c(16:11), hline=3, vline=2, type="b")
 
# Wenn die Namen der Parameter angegeben werden,
# dann spielt auch die Reihenfolge beim Aufruf keine Rolle
plot.mein(hline=3, x=c(1:6), vline=2, y=c(16:11), type="b")

Man kann auch die Standard-Parameter der Ausgangsfunktion ändern. Dazu muss der Parameter in der Definition der eigenen Funktion mit dem gewünschten Wert eingetragen werden (hier: type="o"). Der Parameter muss zusätzlich explizit an die Ausgangsfunktion übergeben werden (hier: type=type).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Ändere den Standardwert für type
plot.mein <- function(..., hline=NULL, vline=NULL, type="o") {
  # type muss explizit übergben werden
  plot(..., type=type)
 
  # [...]
 
}
 
# Der in plot.mein() festgelegte Standadwert für type ("o") wird verwendet
plot.mein(c(1:6), c(16:11), hline=3, vline=2)
 
# Hier wird der beim Aufruf angegebene Wert für type ("b") verwendet
plot.mein(c(1:6), c(16:11), hline=3, vline=2, type="b")