tibble cookbook

1 创建一个tibble

1.1 tibble()函数

使用tibble()可以创建新的tibble对象,但是一般用来创建比较简单的tibble。

library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.0 ──
## ✓ ggplot2 3.3.3     ✓ purrr   0.3.4
## ✓ tibble  3.1.0     ✓ dplyr   1.0.4
## ✓ tidyr   1.1.3     ✓ stringr 1.4.0
## ✓ readr   1.4.0     ✓ forcats 0.5.0
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()
a <- 1
b <- 2:6
tibble(a, b)
## # A tibble: 5 x 2
##       a     b
##   <dbl> <int>
## 1     1     2
## 2     1     3
## 3     1     4
## 4     1     5
## 5     1     6
# 使用下列方法修改列名
tibble(column1 = a, column2 = b)
## # A tibble: 5 x 2
##   column1 column2
##     <dbl>   <int>
## 1       1       2
## 2       1       3
## 3       1       4
## 4       1       5
## 5       1       6

需要注意的是,如果输入的vector长度不一致,只有其中某一个长度为1,才会循环补齐,否则报错.

tibble()函数有一个参数可以注意一下:.name_repair,用来控制对那些不如何规矩的列名如何处理.常用的一共有4个选项:

  • minimal 对列名不做任何处理,既不做列名检查,也不做处理.

  • unique 保证列名都是唯一的并且不能为空.

#如果列名是重复的,会在列名后加入不同的序号.
try(
 tibble(a = 1:3, a = 1:3, 1:3, .name_repair = "unique") 
)
## New names:
## * a -> a...1
## * a -> a...2
## # A tibble: 3 x 3
##   a...1 a...2 `1:3`
##   <int> <int> <int>
## 1     1     1     1
## 2     2     2     2
## 3     3     3     3
  • check_unique 这是默认的参数设置,不对列名做修改,只做列名检查.
#如果列名是重复的,则会报错
try(
 tibble(a = 1:3, a = 1:3) 
)
## Error : Column name `a` must not be duplicated.
## Use .name_repair to specify repair.
  • universal 保证列名都是唯一的并且符合R语言语法.

如果有相同的列名,会在列名后加入不同的序号.

#如果列名是重复的,则会报错
try(
 tibble(a = 1:3, a = 1:3, .name_repair = "universal") 
)
## New names:
## * a -> a...1
## * a -> a...2
## # A tibble: 3 x 2
##   a...1 a...2
##   <int> <int>
## 1     1     1
## 2     2     2
## 3     3     3

1.2 as_tibble()函数

使用as_tibble()函数可以将已有的matrix和data.frame转变为tibble对象.

test1 <- 
  matrix(1:6, ncol = 2)
tibble::as_tibble(test1)
## Warning: The `x` argument of `as_tibble.matrix()` must have unique column names if `.name_repair` is omitted as of tibble 2.0.0.
## Using compatibility `.name_repair`.
## # A tibble: 3 x 2
##      V1    V2
##   <int> <int>
## 1     1     4
## 2     2     5
## 3     3     6
test2 <- 
  data.frame(a = 1:3, b = 2:4, stringsAsFactors = FALSE)
tibble::as_tibble(test2)
## # A tibble: 3 x 2
##       a     b
##   <int> <int>
## 1     1     2
## 2     2     3
## 3     3     4

as_tibble()函数的参数与tibble()大概相同,另外一个需要注意的的参数是:rownames,用来控制如何处理原有的行名.如果设置为NULL,则去除掉行名(默认),如果设置为NA,则保留原来的列名.设置为一个string vector,则将其设置为新的列名.

1.3 tribble()函数

使用tribble()函数可以用另外一种方法来创建tibble对象.

tibble::tribble(
  ~colA, ~colB,
  ## two columns
  "a",   1,
  "b",   2,
  "c",   3
)
## # A tibble: 3 x 2
##   colA   colB
##   <chr> <dbl>
## 1 a         1
## 2 b         2
## 3 c         3

需要注意的是,tibble和data.frame一样,他们中的元素也可以是list.

tribble(
  ~x,  ~y,
  "a", 1:3,
  "b", 4:6
)
## # A tibble: 2 x 2
##   x     y        
##   <chr> <list>   
## 1 a     <int [3]>
## 2 b     <int [3]>

1.4 enframe()函数

enframe()可以将vector转换为tibble,另外有一个相反的函数,deframe()函数,将tibble/data.frame转变为vector.

enframe(x = 1:3)
## # A tibble: 3 x 2
##    name value
##   <int> <int>
## 1     1     1
## 2     2     2
## 3     3     3
enframe(c(a = 5, b = 7))
## # A tibble: 2 x 2
##   name  value
##   <chr> <dbl>
## 1 a         5
## 2 b         7
enframe(list(one = 1, two = 2:3, three = 4:6))
## # A tibble: 3 x 2
##   name  value    
##   <chr> <list>   
## 1 one   <dbl [1]>
## 2 two   <int [2]>
## 3 three <int [3]>

enframe()的第一个参数是x,必须是一个vector或者list,他会将他的每一个元素的名字组成第一列,而其内容作为第二列转变为一个tibble.也就是说其只能用来创建两列的tibble.两列的列名默认为name和value如果想要修改,可以更改两个参数(name和value).

使用deframe()函数将一个一列或者两列的tibble转变为vector或者list.

deframe(enframe(1:3))
## 1 2 3 
## 1 2 3

2 tibble显示控制

tibble默认情况下只输出前十行内容,列自动适应屏幕宽度,如果想要输出比默认更多的数据,有以下几种方法.

2.1 使用print()函数

使用print()函数,可以控制行数和列数.

library(tidyverse)
# 默认显示
nycflights13::flights
## # A tibble: 336,776 x 19
##     year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
##    <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
##  1  2013     1     1      517            515         2      830            819
##  2  2013     1     1      533            529         4      850            830
##  3  2013     1     1      542            540         2      923            850
##  4  2013     1     1      544            545        -1     1004           1022
##  5  2013     1     1      554            600        -6      812            837
##  6  2013     1     1      554            558        -4      740            728
##  7  2013     1     1      555            600        -5      913            854
##  8  2013     1     1      557            600        -3      709            723
##  9  2013     1     1      557            600        -3      838            846
## 10  2013     1     1      558            600        -2      753            745
## # … with 336,766 more rows, and 11 more variables: arr_delay <dbl>,
## #   carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
## #   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>
# 输出15行及所有列数
nycflights13::flights %>% 
  print(n = 15, width = Inf)
## # A tibble: 336,776 x 19
##     year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
##    <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
##  1  2013     1     1      517            515         2      830            819
##  2  2013     1     1      533            529         4      850            830
##  3  2013     1     1      542            540         2      923            850
##  4  2013     1     1      544            545        -1     1004           1022
##  5  2013     1     1      554            600        -6      812            837
##  6  2013     1     1      554            558        -4      740            728
##  7  2013     1     1      555            600        -5      913            854
##  8  2013     1     1      557            600        -3      709            723
##  9  2013     1     1      557            600        -3      838            846
## 10  2013     1     1      558            600        -2      753            745
## 11  2013     1     1      558            600        -2      849            851
## 12  2013     1     1      558            600        -2      853            856
## 13  2013     1     1      558            600        -2      924            917
## 14  2013     1     1      558            600        -2      923            937
## 15  2013     1     1      559            600        -1      941            910
##    arr_delay carrier flight tailnum origin dest  air_time distance  hour minute
##        <dbl> <chr>    <int> <chr>   <chr>  <chr>    <dbl>    <dbl> <dbl>  <dbl>
##  1        11 UA        1545 N14228  EWR    IAH        227     1400     5     15
##  2        20 UA        1714 N24211  LGA    IAH        227     1416     5     29
##  3        33 AA        1141 N619AA  JFK    MIA        160     1089     5     40
##  4       -18 B6         725 N804JB  JFK    BQN        183     1576     5     45
##  5       -25 DL         461 N668DN  LGA    ATL        116      762     6      0
##  6        12 UA        1696 N39463  EWR    ORD        150      719     5     58
##  7        19 B6         507 N516JB  EWR    FLL        158     1065     6      0
##  8       -14 EV        5708 N829AS  LGA    IAD         53      229     6      0
##  9        -8 B6          79 N593JB  JFK    MCO        140      944     6      0
## 10         8 AA         301 N3ALAA  LGA    ORD        138      733     6      0
## 11        -2 B6          49 N793JB  JFK    PBI        149     1028     6      0
## 12        -3 B6          71 N657JB  JFK    TPA        158     1005     6      0
## 13         7 UA         194 N29129  JFK    LAX        345     2475     6      0
## 14       -14 UA        1124 N53441  EWR    SFO        361     2565     6      0
## 15        31 AA         707 N3DUAA  LGA    DFW        257     1389     6      0
##    time_hour          
##    <dttm>             
##  1 2013-01-01 05:00:00
##  2 2013-01-01 05:00:00
##  3 2013-01-01 05:00:00
##  4 2013-01-01 05:00:00
##  5 2013-01-01 06:00:00
##  6 2013-01-01 05:00:00
##  7 2013-01-01 06:00:00
##  8 2013-01-01 06:00:00
##  9 2013-01-01 06:00:00
## 10 2013-01-01 06:00:00
## 11 2013-01-01 06:00:00
## 12 2013-01-01 06:00:00
## 13 2013-01-01 06:00:00
## 14 2013-01-01 06:00:00
## 15 2013-01-01 06:00:00
## # … with 336,761 more rows

2.2 修改options()默认参数

  • options(tibble.print_max = n, tibble.pring_min = m):如果多于m行,则只打印出n 行.options(tibble.print_min = Inf)表示总是打印所有行.

  • options(tibble.width = Inf)表示总是打印所有列,不考虑屏幕的宽度.

options()中所有和tibble相关的参数:

  1. tibble.print_max:Row number threshold: Maximum number of rows printed. Set to Inf to always print all rows. Default: 20.

  2. tibble.print_min: 如果设置为m,意思即为如果行数大于m,则只打印出前n行.

  3. tibble.width: 打印列的宽度.默认为NULL,也就是适应屏幕宽度.设置为Inf,则打印出全部列.

  4. tibble.max_extra_cols: Number of extra columns printed in reduced form. Default: 100.

  5. pillar.bold: pillar是柱子的意思.如果设置为TRUE,则列名为粗体,默认为FALSE,因为在terminal中很多字体对粗体支持不够.

  6. pillar.subtle: 是否打印出其他详细的信息,比如总的行和列数.默认为TRUE.

  7. pillar.subtle_num: Use subtle style for insignificant digits? Default: FALSE, is also affected by the pillar.subtle option.

  8. pillar.neg: 是否高亮负值.默认为TRUE.

  9. pillar.sigfig: 高亮那些数字,比如如果设置为3,则会高亮数字3.

  10. pillar.min_title_chars: 列名打印时最小的字符数,默认为15.意味着如果某些列名大于15,则会被截断.设置为Inf,打印出完整的列名.


3 tibble切片操作

如何取出一个tibble的一列或者几列.

test <- as_tibble(mtcars)
test[,1, drop = TRUE]
##  [1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2 10.4
## [16] 10.4 14.7 32.4 30.4 33.9 21.5 15.5 15.2 13.3 19.2 27.3 26.0 30.4 15.8 19.7
## [31] 15.0 21.4
mtcars[,1]
##  [1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2 10.4
## [16] 10.4 14.7 32.4 30.4 33.9 21.5 15.5 15.2 13.3 19.2 27.3 26.0 30.4 15.8 19.7
## [31] 15.0 21.4

tibble如果使用[函数来进行选择某一列,则默认出来的还是一个tibble,当然可以使用drop参数来设置为TRUE,让其转变成一个vector.而对于data.frame,则取出一列,默认为vector.

test$mpg
##  [1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2 10.4
## [16] 10.4 14.7 32.4 30.4 33.9 21.5 15.5 15.2 13.3 19.2 27.3 26.0 30.4 15.8 19.7
## [31] 15.0 21.4
test[["mpg"]]
##  [1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2 10.4
## [16] 10.4 14.7 32.4 30.4 33.9 21.5 15.5 15.2 13.3 19.2 27.3 26.0 30.4 15.8 19.7
## [31] 15.0 21.4

当然还可以使用$[[函数,这两个函数取出来的都是vector.

library(tidyverse)
test %>% 
  pull(mpg)
##  [1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2 10.4
## [16] 10.4 14.7 32.4 30.4 33.9 21.5 15.5 15.2 13.3 19.2 27.3 26.0 30.4 15.8 19.7
## [31] 15.0 21.4

当然,还可以使用dplyr中的pull()函数,取出来的也是vector.

4 tibble添加新的列或者行

4.1 添加新的行

使用add_row()函数可以给已有的tibble对象添加新的行.

df <- tibble(x = 1:3, y = 3:1)
add_row(df, x = 4, y = 0)
## # A tibble: 4 x 2
##       x     y
##   <dbl> <dbl>
## 1     1     3
## 2     2     2
## 3     3     1
## 4     4     0

可以通过设置.before.after参数来指定插入的位置.默认都是NULL,插入到最后的位置.

add_row(df, x = 4, y = 0, .before = 1)
## # A tibble: 4 x 2
##       x     y
##   <dbl> <dbl>
## 1     4     0
## 2     1     3
## 3     2     2
## 4     3     1
add_row(df, x = 4, y = 0, .before = 2)
## # A tibble: 4 x 2
##       x     y
##   <dbl> <dbl>
## 1     1     3
## 2     4     0
## 3     2     2
## 4     3     1
add_row(df, x = 4, y = 0, .before = 3)
## # A tibble: 4 x 2
##       x     y
##   <dbl> <dbl>
## 1     1     3
## 2     2     2
## 3     4     0
## 4     3     1

.before设置为n,则是指从原来的第n行的前一行开始添加.

add_row(df, x = 4, y = 0, .after = 1)
## # A tibble: 4 x 2
##       x     y
##   <dbl> <dbl>
## 1     1     3
## 2     4     0
## 3     2     2
## 4     3     1
add_row(df, x = 4, y = 0, .after = 2)
## # A tibble: 4 x 2
##       x     y
##   <dbl> <dbl>
## 1     1     3
## 2     2     2
## 3     4     0
## 4     3     1
add_row(df, x = 4, y = 0, .after = 3)
## # A tibble: 4 x 2
##       x     y
##   <dbl> <dbl>
## 1     1     3
## 2     2     2
## 3     3     1
## 4     4     0

.after设置为m,则是指从原来的第m行的后面一行开始添加.

如果某些行不提供新的元素,则会变为NA.

add_row(df, x = 4)
## # A tibble: 4 x 2
##       x     y
##   <dbl> <int>
## 1     1     3
## 2     2     2
## 3     3     1
## 4     4    NA

4.2 添加新的列

使用add_column()函数可以给已有的tibble对象添加新的列.跟add_column()一样的.

# add_column ---------------------------------
df <- tibble(x = 1:3, y = 3:1)
add_column(df, z = -1:1, w = 0)
## # A tibble: 3 x 4
##       x     y     z     w
##   <int> <int> <int> <dbl>
## 1     1     3    -1     0
## 2     2     2     0     0
## 3     3     1     1     0

需要注意的是,并不能覆盖原来的列以及和原来的行数不一样的新的列.

# You can't overwrite existing columns
try(
add_column(df, x = 4:6)  
)
## Error : Column name `x` must not be duplicated.
## Use .name_repair to specify repair.
# You can't create new observations
try(
 add_column(df, z = 1:5) 
)
## Error : New columns must be compatible with `.data`.
## x New column has 5 rows.
## ℹ `.data` has 3 rows.

所以其实并不方便,还是使用dplyr更方便.

5 tibble对列名和行名的操作

5.1 判断是否有行名

head(mtcars)
##                    mpg cyl disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4         21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag     21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710        22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive    21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
## Valiant           18.1   6  225 105 2.76 3.460 20.22  1  0    3    1
rownames(mtcars)
##  [1] "Mazda RX4"           "Mazda RX4 Wag"       "Datsun 710"         
##  [4] "Hornet 4 Drive"      "Hornet Sportabout"   "Valiant"            
##  [7] "Duster 360"          "Merc 240D"           "Merc 230"           
## [10] "Merc 280"            "Merc 280C"           "Merc 450SE"         
## [13] "Merc 450SL"          "Merc 450SLC"         "Cadillac Fleetwood" 
## [16] "Lincoln Continental" "Chrysler Imperial"   "Fiat 128"           
## [19] "Honda Civic"         "Toyota Corolla"      "Toyota Corona"      
## [22] "Dodge Challenger"    "AMC Javelin"         "Camaro Z28"         
## [25] "Pontiac Firebird"    "Fiat X1-9"           "Porsche 914-2"      
## [28] "Lotus Europa"        "Ford Pantera L"      "Ferrari Dino"       
## [31] "Maserati Bora"       "Volvo 142E"
has_rownames(mtcars)
## [1] TRUE
head(iris)
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1          5.1         3.5          1.4         0.2  setosa
## 2          4.9         3.0          1.4         0.2  setosa
## 3          4.7         3.2          1.3         0.2  setosa
## 4          4.6         3.1          1.5         0.2  setosa
## 5          5.0         3.6          1.4         0.2  setosa
## 6          5.4         3.9          1.7         0.4  setosa
rownames(iris)
##   [1] "1"   "2"   "3"   "4"   "5"   "6"   "7"   "8"   "9"   "10"  "11"  "12" 
##  [13] "13"  "14"  "15"  "16"  "17"  "18"  "19"  "20"  "21"  "22"  "23"  "24" 
##  [25] "25"  "26"  "27"  "28"  "29"  "30"  "31"  "32"  "33"  "34"  "35"  "36" 
##  [37] "37"  "38"  "39"  "40"  "41"  "42"  "43"  "44"  "45"  "46"  "47"  "48" 
##  [49] "49"  "50"  "51"  "52"  "53"  "54"  "55"  "56"  "57"  "58"  "59"  "60" 
##  [61] "61"  "62"  "63"  "64"  "65"  "66"  "67"  "68"  "69"  "70"  "71"  "72" 
##  [73] "73"  "74"  "75"  "76"  "77"  "78"  "79"  "80"  "81"  "82"  "83"  "84" 
##  [85] "85"  "86"  "87"  "88"  "89"  "90"  "91"  "92"  "93"  "94"  "95"  "96" 
##  [97] "97"  "98"  "99"  "100"
##  [ reached getOption("max.print") -- omitted 50 entries ]
has_rownames(iris)
## [1] FALSE

可以使用remove_rownames()函数去除掉行名.当然也可以使用将行名设置为NULL打到目的

has_rownames(mtcars)
## [1] TRUE
mtcars2 <- 
  remove_rownames(mtcars)
has_rownames(mtcars2)
## [1] FALSE

5.2 行名和某一列互相转换

rownames_to_column()函数可以将tibble的行名转变为某一列,并且删除掉行名.

mtcars2 <- 
rownames_to_column(mtcars, var = "test")
mtcars2 %>% 
  as_tibble()
## # A tibble: 32 x 12
##    test          mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
##    <chr>       <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
##  1 Mazda RX4    21       6  160    110  3.9   2.62  16.5     0     1     4     4
##  2 Mazda RX4 …  21       6  160    110  3.9   2.88  17.0     0     1     4     4
##  3 Datsun 710   22.8     4  108     93  3.85  2.32  18.6     1     1     4     1
##  4 Hornet 4 D…  21.4     6  258    110  3.08  3.22  19.4     1     0     3     1
##  5 Hornet Spo…  18.7     8  360    175  3.15  3.44  17.0     0     0     3     2
##  6 Valiant      18.1     6  225    105  2.76  3.46  20.2     1     0     3     1
##  7 Duster 360   14.3     8  360    245  3.21  3.57  15.8     0     0     3     4
##  8 Merc 240D    24.4     4  147.    62  3.69  3.19  20       1     0     4     2
##  9 Merc 230     22.8     4  141.    95  3.92  3.15  22.9     1     0     4     2
## 10 Merc 280     19.2     6  168.   123  3.92  3.44  18.3     1     0     4     4
## # … with 22 more rows

另外一个函数,rowid_to_column()可以去除掉行名,并在最开始添加一列rowid,从1开始.

rowid_to_column(mtcars) %>% 
  as_tibble()
## # A tibble: 32 x 12
##    rowid   mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
##    <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
##  1     1  21       6  160    110  3.9   2.62  16.5     0     1     4     4
##  2     2  21       6  160    110  3.9   2.88  17.0     0     1     4     4
##  3     3  22.8     4  108     93  3.85  2.32  18.6     1     1     4     1
##  4     4  21.4     6  258    110  3.08  3.22  19.4     1     0     3     1
##  5     5  18.7     8  360    175  3.15  3.44  17.0     0     0     3     2
##  6     6  18.1     6  225    105  2.76  3.46  20.2     1     0     3     1
##  7     7  14.3     8  360    245  3.21  3.57  15.8     0     0     3     4
##  8     8  24.4     4  147.    62  3.69  3.19  20       1     0     4     2
##  9     9  22.8     4  141.    95  3.92  3.15  22.9     1     0     4     2
## 10    10  19.2     6  168.   123  3.92  3.44  18.3     1     0     4     4
## # … with 22 more rows

当然也可以将某一列变为行名:column_to_rownames().注意必须要求tibble没有行名,且新的行名是没有重复元素的.

column_to_rownames(mtcars2, var = "test")
##                    mpg cyl  disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4         21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag     21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710        22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive    21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout 18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
## Valiant           18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
## Duster 360        14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
## Merc 240D         24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
## Merc 230          22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
##  [ reached 'max' / getOption("max.print") -- omitted 23 rows ]
Avatar
Xiaotao Shen
Postdoctoral Research Fellow

Metabolomics, Multi-omics, Bioinformatics, Systems Biology.

Related

Next
Previous
comments powered by Disqus