@@ -482,6 +482,104 @@ def from_lists(cls, df, base_columns=None, list_columns=None, name="nested"):
482
482
else :
483
483
return NestedFrame (packed_df .to_frame ())
484
484
485
+ def drop (
486
+ self , labels = None , * , axis = 0 , index = None , columns = None , level = None , inplace = False , errors = "raise"
487
+ ):
488
+ """Drop specified labels from rows or columns.
489
+
490
+ Remove rows or columns by specifying label names and corresponding
491
+ axis, or by directly specifying index or column names. When using a
492
+ multi-index, labels on different levels can be removed by
493
+ specifying the level. See the user guide for more information about
494
+ the now unused levels.
495
+
496
+ Parameters
497
+ ----------
498
+ labels: single label or list-like
499
+ Index or column labels to drop. A tuple will be used as a single
500
+ label and not treated as a list-like. Nested sub-columns are
501
+ accessed using dot notation (e.g. "nested.col1").
502
+ axis: {0 or ‘index’, 1 or ‘columns’}, default 0
503
+ Whether to drop labels from the index (0 or ‘index’) or
504
+ columns (1 or ‘columns’).
505
+ index: single label or list-like
506
+ Alternative to specifying axis (labels, axis=0 is equivalent to
507
+ index=labels).
508
+ columns: single label or list-like
509
+ Alternative to specifying axis (labels, axis=1 is equivalent to
510
+ columns=labels).
511
+ level: int or level name, optional
512
+ For MultiIndex, level from which the labels will be removed.
513
+ inplace: bool, default False
514
+ If False, return a copy. Otherwise, do operation in place and
515
+ return None.
516
+ errors: {‘ignore’, ‘raise’}, default ‘raise’
517
+ If ‘ignore’, suppress error and only existing labels are dropped.
518
+
519
+ Returns
520
+ -------
521
+ DataFrame or None
522
+ Returns DataFrame or None DataFrame with the specified index or
523
+ column labels removed or None if inplace=True.
524
+
525
+ Examples
526
+ --------
527
+
528
+ >>> from nested_pandas.datasets.generation import generate_data
529
+ >>> nf = generate_data(5,5, seed=1)
530
+
531
+ >>> # drop the "t" column from "nested"
532
+ >>> nf = nf.drop(["nested.t"], axis=1)
533
+ >>> nf
534
+ a b nested
535
+ 0 0.417022 0.184677 [{flux: 31.551563, band: 'r'}; …] (5 rows)
536
+ 1 0.720324 0.372520 [{flux: 68.650093, band: 'g'}; …] (5 rows)
537
+ 2 0.000114 0.691121 [{flux: 83.462567, band: 'g'}; …] (5 rows)
538
+ 3 0.302333 0.793535 [{flux: 1.828828, band: 'g'}; …] (5 rows)
539
+ 4 0.146756 1.077633 [{flux: 75.014431, band: 'g'}; …] (5 rows)
540
+ """
541
+
542
+ # axis 1 requires special handling for nested columns
543
+ if axis == 1 :
544
+ # label convergence
545
+ if isinstance (labels , str ):
546
+ labels = [labels ]
547
+ nested_labels = [label for label in labels if self ._is_known_hierarchical_column (label )]
548
+ base_labels = [label for label in labels if not self ._is_known_hierarchical_column (label )]
549
+
550
+ # split nested_labels by nested column
551
+ if len (nested_labels ) > 0 :
552
+ nested_cols = set ([label .split ("." )[0 ] for label in nested_labels ])
553
+
554
+ # drop targeted sub-columns for each nested column
555
+ for col in nested_cols :
556
+ sub_cols = [label .split ("." )[1 ] for label in nested_labels if label .split ("." )[0 ] == col ]
557
+ self = self .assign (** {f"{ col } " : self [col ].nest .without_field (sub_cols )})
558
+
559
+ # drop remaining base columns
560
+ if len (base_labels ) > 0 :
561
+ return super ().drop (
562
+ labels = base_labels ,
563
+ axis = axis ,
564
+ index = index ,
565
+ columns = columns ,
566
+ level = level ,
567
+ inplace = inplace ,
568
+ errors = errors ,
569
+ )
570
+ else :
571
+ return self
572
+ # Otherwise just drop like pandas
573
+ return super ().drop (
574
+ labels = labels ,
575
+ axis = axis ,
576
+ index = index ,
577
+ columns = columns ,
578
+ level = level ,
579
+ inplace = inplace ,
580
+ errors = errors ,
581
+ )
582
+
485
583
def eval (self , expr : str , * , inplace : bool = False , ** kwargs ) -> Any | None :
486
584
"""
487
585
0 commit comments