polars-df 0.4.0-x86_64-linux → 0.6.0-x86_64-linux

Sign up to get free protection for your applications and to get access to all the features.
@@ -15,7 +15,7 @@ module Polars
15
15
  #
16
16
  # @example
17
17
  # df = Polars::DataFrame.new({"foo" => [1, 2], "bar" => [["a", "b"], ["c"]]})
18
- # df.select(Polars.col("bar").arr.lengths)
18
+ # df.select(Polars.col("bar").list.lengths)
19
19
  # # =>
20
20
  # # shape: (2, 1)
21
21
  # # ┌─────┐
@@ -27,7 +27,7 @@ module Polars
27
27
  # # │ 1 │
28
28
  # # └─────┘
29
29
  def lengths
30
- Utils.wrap_expr(_rbexpr.arr_lengths)
30
+ Utils.wrap_expr(_rbexpr.list_lengths)
31
31
  end
32
32
 
33
33
  # Sum all the lists in the array.
@@ -36,7 +36,7 @@ module Polars
36
36
  #
37
37
  # @example
38
38
  # df = Polars::DataFrame.new({"values" => [[1], [2, 3]]})
39
- # df.select(Polars.col("values").arr.sum)
39
+ # df.select(Polars.col("values").list.sum)
40
40
  # # =>
41
41
  # # shape: (2, 1)
42
42
  # # ┌────────┐
@@ -48,7 +48,7 @@ module Polars
48
48
  # # │ 5 │
49
49
  # # └────────┘
50
50
  def sum
51
- Utils.wrap_expr(_rbexpr.lst_sum)
51
+ Utils.wrap_expr(_rbexpr.list_sum)
52
52
  end
53
53
 
54
54
  # Compute the max value of the lists in the array.
@@ -57,7 +57,7 @@ module Polars
57
57
  #
58
58
  # @example
59
59
  # df = Polars::DataFrame.new({"values" => [[1], [2, 3]]})
60
- # df.select(Polars.col("values").arr.max)
60
+ # df.select(Polars.col("values").list.max)
61
61
  # # =>
62
62
  # # shape: (2, 1)
63
63
  # # ┌────────┐
@@ -69,7 +69,7 @@ module Polars
69
69
  # # │ 3 │
70
70
  # # └────────┘
71
71
  def max
72
- Utils.wrap_expr(_rbexpr.lst_max)
72
+ Utils.wrap_expr(_rbexpr.list_max)
73
73
  end
74
74
 
75
75
  # Compute the min value of the lists in the array.
@@ -78,7 +78,7 @@ module Polars
78
78
  #
79
79
  # @example
80
80
  # df = Polars::DataFrame.new({"values" => [[1], [2, 3]]})
81
- # df.select(Polars.col("values").arr.min)
81
+ # df.select(Polars.col("values").list.min)
82
82
  # # =>
83
83
  # # shape: (2, 1)
84
84
  # # ┌────────┐
@@ -90,7 +90,7 @@ module Polars
90
90
  # # │ 2 │
91
91
  # # └────────┘
92
92
  def min
93
- Utils.wrap_expr(_rbexpr.lst_min)
93
+ Utils.wrap_expr(_rbexpr.list_min)
94
94
  end
95
95
 
96
96
  # Compute the mean value of the lists in the array.
@@ -99,7 +99,7 @@ module Polars
99
99
  #
100
100
  # @example
101
101
  # df = Polars::DataFrame.new({"values" => [[1], [2, 3]]})
102
- # df.select(Polars.col("values").arr.mean)
102
+ # df.select(Polars.col("values").list.mean)
103
103
  # # =>
104
104
  # # shape: (2, 1)
105
105
  # # ┌────────┐
@@ -111,7 +111,7 @@ module Polars
111
111
  # # │ 2.5 │
112
112
  # # └────────┘
113
113
  def mean
114
- Utils.wrap_expr(_rbexpr.lst_mean)
114
+ Utils.wrap_expr(_rbexpr.list_mean)
115
115
  end
116
116
 
117
117
  # Sort the arrays in the list.
@@ -124,7 +124,7 @@ module Polars
124
124
  # "a" => [[3, 2, 1], [9, 1, 2]]
125
125
  # }
126
126
  # )
127
- # df.select(Polars.col("a").arr.sort)
127
+ # df.select(Polars.col("a").list.sort)
128
128
  # # =>
129
129
  # # shape: (2, 1)
130
130
  # # ┌───────────┐
@@ -136,7 +136,7 @@ module Polars
136
136
  # # │ [1, 2, 9] │
137
137
  # # └───────────┘
138
138
  def sort(reverse: false)
139
- Utils.wrap_expr(_rbexpr.lst_sort(reverse))
139
+ Utils.wrap_expr(_rbexpr.list_sort(reverse))
140
140
  end
141
141
 
142
142
  # Reverse the arrays in the list.
@@ -149,7 +149,7 @@ module Polars
149
149
  # "a" => [[3, 2, 1], [9, 1, 2]]
150
150
  # }
151
151
  # )
152
- # df.select(Polars.col("a").arr.reverse)
152
+ # df.select(Polars.col("a").list.reverse)
153
153
  # # =>
154
154
  # # shape: (2, 1)
155
155
  # # ┌───────────┐
@@ -161,7 +161,7 @@ module Polars
161
161
  # # │ [2, 1, 9] │
162
162
  # # └───────────┘
163
163
  def reverse
164
- Utils.wrap_expr(_rbexpr.lst_reverse)
164
+ Utils.wrap_expr(_rbexpr.list_reverse)
165
165
  end
166
166
 
167
167
  # Get the unique/distinct values in the list.
@@ -174,7 +174,7 @@ module Polars
174
174
  # "a" => [[1, 1, 2]]
175
175
  # }
176
176
  # )
177
- # df.select(Polars.col("a").arr.unique)
177
+ # df.select(Polars.col("a").list.unique)
178
178
  # # =>
179
179
  # # shape: (1, 1)
180
180
  # # ┌───────────┐
@@ -184,8 +184,8 @@ module Polars
184
184
  # # ╞═══════════╡
185
185
  # # │ [1, 2] │
186
186
  # # └───────────┘
187
- def unique
188
- Utils.wrap_expr(_rbexpr.lst_unique)
187
+ def unique(maintain_order: false)
188
+ Utils.wrap_expr(_rbexpr.list_unique(maintain_order))
189
189
  end
190
190
 
191
191
  # Concat the arrays in a Series dtype List in linear time.
@@ -202,7 +202,7 @@ module Polars
202
202
  # "b" => [["b", "c"], ["y", "z"]]
203
203
  # }
204
204
  # )
205
- # df.select(Polars.col("a").arr.concat("b"))
205
+ # df.select(Polars.col("a").list.concat("b"))
206
206
  # # =>
207
207
  # # shape: (2, 1)
208
208
  # # ┌─────────────────┐
@@ -214,11 +214,11 @@ module Polars
214
214
  # # │ ["x", "y", "z"] │
215
215
  # # └─────────────────┘
216
216
  def concat(other)
217
- if other.is_a?(Array) && ![Expr, String, Series].any? { |c| other[0].is_a?(c) }
217
+ if other.is_a?(::Array) && ![Expr, String, Series].any? { |c| other[0].is_a?(c) }
218
218
  return concat(Series.new([other]))
219
219
  end
220
220
 
221
- if !other.is_a?(Array)
221
+ if !other.is_a?(::Array)
222
222
  other_list = [other]
223
223
  else
224
224
  other_list = other.dup
@@ -241,7 +241,7 @@ module Polars
241
241
  #
242
242
  # @example
243
243
  # df = Polars::DataFrame.new({"foo" => [[3, 2, 1], [], [1, 2]]})
244
- # df.select(Polars.col("foo").arr.get(0))
244
+ # df.select(Polars.col("foo").list.get(0))
245
245
  # # =>
246
246
  # # shape: (3, 1)
247
247
  # # ┌──────┐
@@ -254,8 +254,8 @@ module Polars
254
254
  # # │ 1 │
255
255
  # # └──────┘
256
256
  def get(index)
257
- index = Utils.expr_to_lit_or_expr(index, str_to_lit: false)._rbexpr
258
- Utils.wrap_expr(_rbexpr.lst_get(index))
257
+ index = Utils.parse_as_expression(index)
258
+ Utils.wrap_expr(_rbexpr.list_get(index))
259
259
  end
260
260
 
261
261
  # Get the value by index in the sublists.
@@ -265,13 +265,35 @@ module Polars
265
265
  get(item)
266
266
  end
267
267
 
268
+ # Take sublists by multiple indices.
269
+ #
270
+ # The indices may be defined in a single column, or by sublists in another
271
+ # column of dtype `List`.
272
+ #
273
+ # @param index [Object]
274
+ # Indices to return per sublist
275
+ # @param null_on_oob [Boolean]
276
+ # Behavior if an index is out of bounds:
277
+ # True -> set as null
278
+ # False -> raise an error
279
+ # Note that defaulting to raising an error is much cheaper
280
+ #
281
+ # @return [Expr]
282
+ def take(index, null_on_oob: false)
283
+ if index.is_a?(::Array)
284
+ index = Series.new(index)
285
+ end
286
+ index = Utils.expr_to_lit_or_expr(index, str_to_lit: false)._rbexpr
287
+ Utils.wrap_expr(_rbexpr.list_take(index, null_on_oob))
288
+ end
289
+
268
290
  # Get the first value of the sublists.
269
291
  #
270
292
  # @return [Expr]
271
293
  #
272
294
  # @example
273
295
  # df = Polars::DataFrame.new({"foo" => [[3, 2, 1], [], [1, 2]]})
274
- # df.select(Polars.col("foo").arr.first)
296
+ # df.select(Polars.col("foo").list.first)
275
297
  # # =>
276
298
  # # shape: (3, 1)
277
299
  # # ┌──────┐
@@ -293,7 +315,7 @@ module Polars
293
315
  #
294
316
  # @example
295
317
  # df = Polars::DataFrame.new({"foo" => [[3, 2, 1], [], [1, 2]]})
296
- # df.select(Polars.col("foo").arr.last)
318
+ # df.select(Polars.col("foo").list.last)
297
319
  # # =>
298
320
  # # shape: (3, 1)
299
321
  # # ┌──────┐
@@ -318,7 +340,7 @@ module Polars
318
340
  #
319
341
  # @example
320
342
  # df = Polars::DataFrame.new({"foo" => [[3, 2, 1], [], [1, 2]]})
321
- # df.select(Polars.col("foo").arr.contains(1))
343
+ # df.select(Polars.col("foo").list.contains(1))
322
344
  # # =>
323
345
  # # shape: (3, 1)
324
346
  # # ┌───────┐
@@ -331,7 +353,7 @@ module Polars
331
353
  # # │ true │
332
354
  # # └───────┘
333
355
  def contains(item)
334
- Utils.wrap_expr(_rbexpr.arr_contains(Utils.expr_to_lit_or_expr(item)._rbexpr))
356
+ Utils.wrap_expr(_rbexpr.list_contains(Utils.expr_to_lit_or_expr(item)._rbexpr))
335
357
  end
336
358
 
337
359
  # Join all string items in a sublist and place a separator between them.
@@ -345,7 +367,7 @@ module Polars
345
367
  #
346
368
  # @example
347
369
  # df = Polars::DataFrame.new({"s" => [["a", "b", "c"], ["x", "y"]]})
348
- # df.select(Polars.col("s").arr.join(" "))
370
+ # df.select(Polars.col("s").list.join(" "))
349
371
  # # =>
350
372
  # # shape: (2, 1)
351
373
  # # ┌───────┐
@@ -357,7 +379,7 @@ module Polars
357
379
  # # │ x y │
358
380
  # # └───────┘
359
381
  def join(separator)
360
- Utils.wrap_expr(_rbexpr.lst_join(separator))
382
+ Utils.wrap_expr(_rbexpr.list_join(separator))
361
383
  end
362
384
 
363
385
  # Retrieve the index of the minimal value in every sublist.
@@ -370,7 +392,7 @@ module Polars
370
392
  # "a" => [[1, 2], [2, 1]]
371
393
  # }
372
394
  # )
373
- # df.select(Polars.col("a").arr.arg_min)
395
+ # df.select(Polars.col("a").list.arg_min)
374
396
  # # =>
375
397
  # # shape: (2, 1)
376
398
  # # ┌─────┐
@@ -382,7 +404,7 @@ module Polars
382
404
  # # │ 1 │
383
405
  # # └─────┘
384
406
  def arg_min
385
- Utils.wrap_expr(_rbexpr.lst_arg_min)
407
+ Utils.wrap_expr(_rbexpr.list_arg_min)
386
408
  end
387
409
 
388
410
  # Retrieve the index of the maximum value in every sublist.
@@ -395,7 +417,7 @@ module Polars
395
417
  # "a" => [[1, 2], [2, 1]]
396
418
  # }
397
419
  # )
398
- # df.select(Polars.col("a").arr.arg_max)
420
+ # df.select(Polars.col("a").list.arg_max)
399
421
  # # =>
400
422
  # # shape: (2, 1)
401
423
  # # ┌─────┐
@@ -407,7 +429,7 @@ module Polars
407
429
  # # │ 0 │
408
430
  # # └─────┘
409
431
  def arg_max
410
- Utils.wrap_expr(_rbexpr.lst_arg_max)
432
+ Utils.wrap_expr(_rbexpr.list_arg_max)
411
433
  end
412
434
 
413
435
  # Calculate the n-th discrete difference of every sublist.
@@ -421,7 +443,7 @@ module Polars
421
443
  #
422
444
  # @example
423
445
  # s = Polars::Series.new("a", [[1, 2, 3, 4], [10, 2, 1]])
424
- # s.arr.diff
446
+ # s.list.diff
425
447
  # # =>
426
448
  # # shape: (2,)
427
449
  # # Series: 'a' [list[i64]]
@@ -430,7 +452,7 @@ module Polars
430
452
  # # [null, -8, -1]
431
453
  # # ]
432
454
  def diff(n: 1, null_behavior: "ignore")
433
- Utils.wrap_expr(_rbexpr.lst_diff(n, null_behavior))
455
+ Utils.wrap_expr(_rbexpr.list_diff(n, null_behavior))
434
456
  end
435
457
 
436
458
  # Shift values by the given period.
@@ -442,7 +464,7 @@ module Polars
442
464
  #
443
465
  # @example
444
466
  # s = Polars::Series.new("a", [[1, 2, 3, 4], [10, 2, 1]])
445
- # s.arr.shift
467
+ # s.list.shift
446
468
  # # =>
447
469
  # # shape: (2,)
448
470
  # # Series: 'a' [list[i64]]
@@ -451,7 +473,7 @@ module Polars
451
473
  # # [null, 10, 2]
452
474
  # # ]
453
475
  def shift(periods = 1)
454
- Utils.wrap_expr(_rbexpr.lst_shift(periods))
476
+ Utils.wrap_expr(_rbexpr.list_shift(periods))
455
477
  end
456
478
 
457
479
  # Slice every sublist.
@@ -466,7 +488,7 @@ module Polars
466
488
  #
467
489
  # @example
468
490
  # s = Polars::Series.new("a", [[1, 2, 3, 4], [10, 2, 1]])
469
- # s.arr.slice(1, 2)
491
+ # s.list.slice(1, 2)
470
492
  # # =>
471
493
  # # shape: (2,)
472
494
  # # Series: 'a' [list[i64]]
@@ -477,7 +499,7 @@ module Polars
477
499
  def slice(offset, length = nil)
478
500
  offset = Utils.expr_to_lit_or_expr(offset, str_to_lit: false)._rbexpr
479
501
  length = Utils.expr_to_lit_or_expr(length, str_to_lit: false)._rbexpr
480
- Utils.wrap_expr(_rbexpr.lst_slice(offset, length))
502
+ Utils.wrap_expr(_rbexpr.list_slice(offset, length))
481
503
  end
482
504
 
483
505
  # Slice the first `n` values of every sublist.
@@ -489,7 +511,7 @@ module Polars
489
511
  #
490
512
  # @example
491
513
  # s = Polars::Series.new("a", [[1, 2, 3, 4], [10, 2, 1]])
492
- # s.arr.head(2)
514
+ # s.list.head(2)
493
515
  # # =>
494
516
  # # shape: (2,)
495
517
  # # Series: 'a' [list[i64]]
@@ -510,7 +532,7 @@ module Polars
510
532
  #
511
533
  # @example
512
534
  # s = Polars::Series.new("a", [[1, 2, 3, 4], [10, 2, 1]])
513
- # s.arr.tail(2)
535
+ # s.list.tail(2)
514
536
  # # =>
515
537
  # # shape: (2,)
516
538
  # # Series: 'a' [list[i64]]
@@ -523,6 +545,33 @@ module Polars
523
545
  slice(offset, n)
524
546
  end
525
547
 
548
+ # Count how often the value produced by ``element`` occurs.
549
+ #
550
+ # @param element [Expr]
551
+ # An expression that produces a single value
552
+ #
553
+ # @return [Expr]
554
+ #
555
+ # @example
556
+ # df = Polars::DataFrame.new({"listcol" => [[0], [1], [1, 2, 3, 2], [1, 2, 1], [4, 4]]})
557
+ # df.select(Polars.col("listcol").list.count_match(2).alias("number_of_twos"))
558
+ # # =>
559
+ # # shape: (5, 1)
560
+ # # ┌────────────────┐
561
+ # # │ number_of_twos │
562
+ # # │ --- │
563
+ # # │ u32 │
564
+ # # ╞════════════════╡
565
+ # # │ 0 │
566
+ # # │ 0 │
567
+ # # │ 2 │
568
+ # # │ 1 │
569
+ # # │ 0 │
570
+ # # └────────────────┘
571
+ def count_match(element)
572
+ Utils.wrap_expr(_rbexpr.list_count_match(Utils.expr_to_lit_or_expr(element)._rbexpr))
573
+ end
574
+
526
575
  # Convert the series of type `List` to a series of type `Struct`.
527
576
  #
528
577
  # @param n_field_strategy ["first_non_null", "max_width"]
@@ -535,7 +584,7 @@ module Polars
535
584
  #
536
585
  # @example
537
586
  # df = Polars::DataFrame.new({"a" => [[1, 2, 3], [1, 2]]})
538
- # df.select([Polars.col("a").arr.to_struct])
587
+ # df.select([Polars.col("a").list.to_struct])
539
588
  # # =>
540
589
  # # shape: (2, 1)
541
590
  # # ┌────────────┐
@@ -548,7 +597,7 @@ module Polars
548
597
  # # └────────────┘
549
598
  def to_struct(n_field_strategy: "first_non_null", name_generator: nil)
550
599
  raise Todo if name_generator
551
- Utils.wrap_expr(_rbexpr.lst_to_struct(n_field_strategy, name_generator, 0))
600
+ Utils.wrap_expr(_rbexpr.list_to_struct(n_field_strategy, name_generator, 0))
552
601
  end
553
602
 
554
603
  # Run any polars expression against the lists' elements.
@@ -568,7 +617,7 @@ module Polars
568
617
  # @example
569
618
  # df = Polars::DataFrame.new({"a" => [1, 8, 3], "b" => [4, 5, 2]})
570
619
  # df.with_column(
571
- # Polars.concat_list(["a", "b"]).arr.eval(Polars.element.rank).alias("rank")
620
+ # Polars.concat_list(["a", "b"]).list.eval(Polars.element.rank).alias("rank")
572
621
  # )
573
622
  # # =>
574
623
  # # shape: (3, 3)
@@ -582,7 +631,7 @@ module Polars
582
631
  # # │ 3 ┆ 2 ┆ [2.0, 1.0] │
583
632
  # # └─────┴─────┴────────────┘
584
633
  def eval(expr, parallel: false)
585
- Utils.wrap_expr(_rbexpr.lst_eval(expr._rbexpr, parallel))
634
+ Utils.wrap_expr(_rbexpr.list_eval(expr._rbexpr, parallel))
586
635
  end
587
636
  end
588
637
  end
@@ -1,9 +1,9 @@
1
1
  module Polars
2
- # Series.arr namespace.
2
+ # Series.list namespace.
3
3
  class ListNameSpace
4
4
  include ExprDispatch
5
5
 
6
- self._accessor = "arr"
6
+ self._accessor = "list"
7
7
 
8
8
  # @private
9
9
  def initialize(series)
@@ -16,7 +16,7 @@ module Polars
16
16
  #
17
17
  # @example
18
18
  # s = Polars::Series.new([[1, 2, 3], [5]])
19
- # s.arr.lengths
19
+ # s.list.lengths
20
20
  # # =>
21
21
  # # shape: (2,)
22
22
  # # Series: '' [u32]
@@ -119,13 +119,13 @@ module Polars
119
119
  #
120
120
  # @example
121
121
  # s = Polars::Series.new([["foo", "bar"], ["hello", "world"]])
122
- # s.arr.join("-")
122
+ # s.list.join("-")
123
123
  # # =>
124
124
  # # shape: (2,)
125
125
  # # Series: '' [str]
126
126
  # # [
127
- # # "foo-bar"
128
- # # "hello-world"
127
+ # # "foo-bar"
128
+ # # "hello-world"
129
129
  # # ]
130
130
  def join(separator)
131
131
  super
@@ -180,7 +180,7 @@ module Polars
180
180
  #
181
181
  # @example
182
182
  # s = Polars::Series.new("a", [[1, 2, 3, 4], [10, 2, 1]])
183
- # s.arr.diff
183
+ # s.list.diff
184
184
  # # =>
185
185
  # # shape: (2,)
186
186
  # # Series: 'a' [list[i64]]
@@ -201,7 +201,7 @@ module Polars
201
201
  #
202
202
  # @example
203
203
  # s = Polars::Series.new("a", [[1, 2, 3, 4], [10, 2, 1]])
204
- # s.arr.shift
204
+ # s.list.shift
205
205
  # # =>
206
206
  # # shape: (2,)
207
207
  # # Series: 'a' [list[i64]]
@@ -225,7 +225,7 @@ module Polars
225
225
  #
226
226
  # @example
227
227
  # s = Polars::Series.new("a", [[1, 2, 3, 4], [10, 2, 1]])
228
- # s.arr.slice(1, 2)
228
+ # s.list.slice(1, 2)
229
229
  # # =>
230
230
  # # shape: (2,)
231
231
  # # Series: 'a' [list[i64]]
@@ -246,7 +246,7 @@ module Polars
246
246
  #
247
247
  # @example
248
248
  # s = Polars::Series.new("a", [[1, 2, 3, 4], [10, 2, 1]])
249
- # s.arr.head(2)
249
+ # s.list.head(2)
250
250
  # # =>
251
251
  # # shape: (2,)
252
252
  # # Series: 'a' [list[i64]]
@@ -267,7 +267,7 @@ module Polars
267
267
  #
268
268
  # @example
269
269
  # s = Polars::Series.new("a", [[1, 2, 3, 4], [10, 2, 1]])
270
- # s.arr.tail(2)
270
+ # s.list.tail(2)
271
271
  # # =>
272
272
  # # shape: (2,)
273
273
  # # Series: 'a' [list[i64]]
@@ -291,7 +291,7 @@ module Polars
291
291
  #
292
292
  # @example
293
293
  # df = Polars::DataFrame.new({"a" => [[1, 2, 3], [1, 2]]})
294
- # df.select([Polars.col("a").arr.to_struct])
294
+ # df.select([Polars.col("a").list.to_struct])
295
295
  # # =>
296
296
  # # shape: (2, 1)
297
297
  # # ┌────────────┐
@@ -323,7 +323,7 @@ module Polars
323
323
  # @example
324
324
  # df = Polars::DataFrame.new({"a" => [1, 8, 3], "b" => [4, 5, 2]})
325
325
  # df.with_column(
326
- # Polars.concat_list(["a", "b"]).arr.eval(Polars.element.rank).alias("rank")
326
+ # Polars.concat_list(["a", "b"]).list.eval(Polars.element.rank).alias("rank")
327
327
  # )
328
328
  # # =>
329
329
  # # shape: (3, 3)
@@ -10,7 +10,8 @@ module Polars
10
10
  period,
11
11
  offset,
12
12
  closed,
13
- by
13
+ by,
14
+ check_sorted
14
15
  )
15
16
  period = Utils._timedelta_to_pl_duration(period)
16
17
  offset = Utils._timedelta_to_pl_duration(offset)
@@ -21,12 +22,13 @@ module Polars
21
22
  @offset = offset
22
23
  @closed = closed
23
24
  @by = by
25
+ @check_sorted = check_sorted
24
26
  end
25
27
 
26
28
  def agg(aggs)
27
29
  @df.lazy
28
30
  .groupby_rolling(
29
- index_column: @time_column, period: @period, offset: @offset, closed: @closed, by: @by
31
+ index_column: @time_column, period: @period, offset: @offset, closed: @closed, by: @by, check_sorted: @check_sorted
30
32
  )
31
33
  .agg(aggs)
32
34
  .collect(no_optimization: true, string_cache: false)