text:
Tell my friends to which "comma club" they belong
Inspired by Silicon Valley's "three-comma club" scenes, like this one, in this challenge you'll be telling ten people the "comma club" to which they each belong.
If you're unfamiliar with the term "comma club," let me explain: you're in the one-comma club if the money you have is in the inclusive range $1,000.00 to $999,999.99; you're in the two-comma club if it's in the range $1,000,000.00 to $999,999,999.99; these "clubs" repeat through the three-comma club, since no individual on Earth (AFAIK) owns more than one trillion U.S. dollars (Japanese Yen would be a different story very quickly). So, the number of commas your bank account has, according to the notation standards most common in the United States and Great Britain, denotes the comma club to which you belong. The same "comma" rules apply for negative numbers (although you wouldn't want to be in the negative comma club): negative amounts in the inclusive range [-0.01, -999.99] belong to the zero-comma club, amounts in the range [-1000.00, -999999.99] belong to the one-comma club, etc.
The test cases
Friend    Amount
John      100000
Jamie     0.05
Kylie     1549001.10
Laura     999999999.99
Russ      986000000
Karla     1
Reid      99.99
Mark      999.99
Manson    1000.01
Lonnie    999999999999.00
Nelly     -123.45

The right answers:
John is in the 1-comma club.
Jamie is in the 0-comma club.
Kylie is in the 2-comma club.
Laura is in the 2-comma club.
Russ is in the 2-comma club.
Karla is in the 0-comma club.
Reid is in the 0-comma club.
Mark is in the 0-comma club.
Manson is in the 1-comma club.
Lonnie is in the 3-comma club.
Nelly is in the 0-comma club.

Whatever array setup you need to get a friends array and amounts array does not count towards your score. So for Python, the following code doesn't count:
f = ['John', 'Jamie', 'Kylie', 'Laura', 'Russ', 'Karla', 'Reid', 'Mark', 'Manson', 'Lonnie']
a = ['100000', '0.05', '1549001.10', '999999999.99', '986000000', '1', '99.99', '999.99', '1000.01', '999999999999.00']

Edit: Please see the revised test cases
I removed the actual string commas from the test cases to make things a bit more difficult, as opposed to just counting commas.

I don't think you've made the output format very clear. Is something like "Name number,Name number,..." acceptable?

Are the entries in f guaranteed to be positive, or would -$1,234.56 also be in the 1-comma club?

@JonathanAllan yes, good point. Technically that's a comma club. The entries are not guaranteed to be positive. You're basically counting the number of commas.

Wait, will we not have commas in the input?

Please see the revised test cases. When I initially thought of this challenge, I wanted to leave out actual commas in the dollar strings above. That change is now reflected.

May we take the numbers in any format desired, e.g. strings?

@R.Kap yes, that's fine.

Can we assume that there will no duplicate names?

@Titus yes, that's fine.

@not_a_robot Could you address Fry's comment? Is it sufficient to output pairs of name and number in any format?

@FryAmTheEggman No, the output needs to be in the format "<name> is in the <number of commas>-club."

The question, ignoring comments (which it's reasonable to assume that people will do when answering) still doesn't specify to which comma club anyone with less than $1000 belongs.

@PeterTaylor Yes, it does. Check out the test cases: Reid has $99.99, and the correct output is Reid is in the 0-comma club.

Test cases are not spec. And even if they were, there's no test case covering the issue of large negatives raised by Jonathan Allan above.

Please edit the question to lay out in detail (not just in test cases) whether negative numbers with commas are part of a club or are always 0-comma club

JavaScript (ES6), 80 bytes
a=>a.map(([s,n])=>s+` is in the ${n.toFixed(n<0?3:4).length/3-2|0}-comma club.`)

Takes an array of [friend, amount] arrays and returns an array of "friend is in the n-comma club." strings. Works by adding extra trailing zeros so that the length is 6-8 for the 0-comma club, 9-11 for the 1-comma club, 12-15 for the 2-comma club etc.
https://jsfiddle.net/cau40vmk/1/

I don't think this works for negative numbers. For instance, it would put Nelly (-123.45) in the 1-comma club. I'd suggest the shorter Math.log10(n*n)/6|0.

@Arnauld Ah yes, I'd forgotten |0 truncates to zero, so it gives the right answer for Jamie.

PostgreSQL, 61 bytes
SELECT f||' is in the '||div(log(@a),3)||'-comma club.'FROM p

@x is the absolute value of x, log(x) is base-10 logarithm and div(y, x) computes the integer quotient of y/x.

Setup:
CREATE TEMP TABLE p AS
SELECT * FROM (VALUES
    ('John', 100000),
    ('Jamie', 0.05),
    ('Kylie', 1549001.10),
    ('Laura', 999999999.99),
    ('Russ', 986000000),
    ('Karla', 1),
    ('Reid', 99.99),
    ('Mark', 999.99),
    ('Manson', 1000.01),
    ('Lonnie', 999999999999.00),
    ('Nelly', -123.45)
) AS p (f, a)

Output:
            ?column?
--------------------------------
 John is in the 1-comma club.
 Jamie is in the 0-comma club.
 Kylie is in the 2-comma club.
 Laura is in the 2-comma club.
 Russ is in the 2-comma club.
 Karla is in the 0-comma club.
 Reid is in the 0-comma club.
 Mark is in the 0-comma club.
 Manson is in the 1-comma club.
 Lonnie is in the 3-comma club.
 Nelly is in the 0-comma club.
(11 rows)

It's nice to see a competitive SQL answer - well done!

Jelly, 34 32  31 bytes
AḞbȷL’⁶;“£ṙƬs⁾`¬ụṂ“¢<ỴȦ8£l»j)⁹żY

A dyadic link (function) which takes a list of bank balances as numbers (decimals / integers) and a list of names as strings and returns a list of strings.
Try it online! - the footer çYsimply calls the function and joins the resulting list with line feeds so it has nice output when run as a full program.
How?
AḞbȷL’⁶;“£ṙƬs⁾`¬ụṂ“¢<ỴȦ8£l»j)⁹ż - Main link: bankBalances, names
                            )   - for each bankBalance:
A                               -   absolute value (treat negatives and positives the same)
 Ḟ                              -   floor (get rid of any pennies)
  bȷ                            -   convert to base 1000
    L                           -   length (number of digits in base 1000)
     ’                          -   decrement by one
      ⁶;                        -   concatenate a space with that   ...because -------.
        “         “       »     -   compressed list of strings:                       ↓
         £ṙƬs⁾`¬ụṂ              -     " is in the"  ← cannot compress a trailing space :(
                   ¢<ỴȦ8£l      -     "-comma club."
                           j    -   join that list of strings with the "number plus space"
                             ⁹  - right argument (names)
                              ż - zip with L

PHP, 76 74 bytes
// data as associative array
$d=[Poorman=>-1234,John=>100000,Jamie=>0.05,Kylie=>1549001.10,Laura=>999999999.99,Russ=>1000000000,Karla=>1,Reid=>99.99,Mark=>999.99,Manson=>1000.01,Lonnie=>999999999999.00];
// code
foreach($d as$n=>$a)printf("$n is in the %d-comma club.
",log($a*$a,1e6));

Fortunately I don´t have to cast to int (as I would have to in C); PHP does that implicitly for %d.

Gee! Am I the first here to calculate instead of counting characters?

Japt, 36 bytes
This takes in the amount as the first input, name as the second.
V+`   e {w0 x4 l /3-2|0}-¬mµ club

Explanation
V+`   e {w0 x4 l /3-2|0}-¬mµ club
V+                                   // Second input +
  `                                  // compressed string:
      e                              // " is in the "
        {              }             // Insert here:
         w0                          //   The larger of 0 and the first input
            x4                       //   Rounded to the 4th decimal
               l                     //   Length
                        -¬mµ club    // "-comma club"
                                     // A closing backtick is auto-inserted at the end of the program

Japt uses the shoco library for string compression.
Inspired by @Neil's solution.
Saved 7 bytes thanks to @ETHproductions
Try it online!

I think you can just do Vw0 x4 l /3-2|0 in the middle section, saving 6 bytes :-)

I think you can save a byte by taking input in the opposite order: V+`...{w0...

Mathematica (86 bytes)
The set-up (with names as strings, money as numbers):
n = {"John", "Jamie", "Kylie", "Laura", "Russ", "Karla", "Reid", "Mark", "Manson", "Lonnie", "Nelly"};
m = {100000, 0.05, 1549001.10, 999999999.99, 1000000000, 1, 99.99, 999.99, 1000.01, 999999999999.00, -123.45}

The attempt:
MapThread[#~~" is in the "~~ToString@Max[Floor@Log[10^3,#2],0]~~"-comma club."&,{n,m}]

All of Mathematica's string functions include "String" in the name, so I think logs are shorter. The Max[...,0] is to deal with the pesky negative numbers or negative infinity for people who own between -1 and 1 dollars. The log of a negative number includes imaginary stuff, but Mathematica helpfully ignores that when taking a Floor!

MATL, 50 48 43 bytes
`j' is in the 'i|kVn3/XkqV'-comma club'&hDT

Try it at MATL Online
Explanation
`                   % Do...While loop
  j                 % Explicitly grab the next input as a string
  ' is in the the ' % Push this string literal to the stack
  i                 % Grab the next input as a number
  |                 % Compute the absolute value
  k                 % Round towards zero
  V                 % Convert to a string
  n3/Xk             % Divide the length of the string by 3 and round up
  q                 % Subtract one
  V                 % Convert to a string
  '-comma club'     % Push this string literal to the stack
  &h                % Horizontally concatenate the entire stack
  D                 % Display the resulting string
  T                 % Push TRUE to the stack, causing an infinite loop which automatically
                    % terminates when we run out of inputs
                    % Implicit end of do...while loop

05AB1E, 32 bytes
Äï€g3/î<“-comma†Ú“«“€ˆ€†€€ “ì‚ø»

Try it online!
Explanation
Ä                                 # absolute value of input
 ï                                # convert to int
  €g                              # length of each
    3/                            # divided by 3
      î                           # round up
       <                          # decrement
        “-comma†Ú“«               # append string "-comma club" to each number
                   “€ˆ€†€€ “ì     # prepend string "is in the " to each number
                             ‚    # pair with second input
                              ø   # zip
                               »  # join by spaces and newlines

R, 68  bytes
The setup:
f <- c('John', 'Jamie', 'Kylie', 'Laura', 'Russ', 'Karla', 'Reid', 'Mark', 'Manson', 'Lonnie', 'Nelly')
a <- c(100000, 0.05, 1549001.10, 999999999.99, 986000000, 1, 99.99, 999.99, 1000.01, 999999999999.00, -123.45)

The solution:
cat(paste0(f, " is in the ",floor(log10(abs(a))/3)),"-comma club.\n"))

Take the base 10 log of the absolute value of the account, round down then print with the names.
I'm not sure if it could be smaller if a would be a character vector...

What about the case of Nelly, who has -123.45 dollars? That log10 call will produce NaNs for negatives. Looks like log10(abs(a)) would work.

Oops, you're right, the sample above didn't include Nelly. And I misread the specification... I understood negative value should be 0 comma club.

Instead of abs(x), use pmax(a,1) - this will take anything less than 1 and make it 1, giving good results for negative numbers. And, instead of floor(log10(...)/3) you can use log10(...)%/%3. I think that gets it down to 66 bytes (and correct for negatives).

Also worth noting that a full 7 bytes of that are the cat() and \n... printing the vector with the strings in it to the console might be considered good enough (*ahem* like the Python answers).

This has an extra parenthesis after 3. It also outputs the -1 club for Jamie. Using pmax(a,1) fixes that.

JavaScript, 59 bytes
Saved 3 bytes thanks to @ETHproductions
Saved 2 bytes thanks to @Cyoce
n=>m=>n+` is in the ${m>1?Math.log10(m)/3|0:0}-comma club.`

Demo

f=n=>m=>n+` is in the ${m>1?Math.log10(m)/3|0:0}-comma club.`

console.log((f("John")(100000)))
console.log((f("Jamie")(0.05)))
console.log((f("Kylie")(1549001.10)))
console.log((f("Laura")(999999999.99)))
console.log((f("Russ")(986000000)))
console.log((f("Karla")(1)))
console.log((f("Reid")(99.99)))
console.log((f("Mark")(999.99)))
console.log((f("Manson")(1000.01)))
console.log((f("Lonnie")(999999999999.00)))
console.log((f("Nelly")(-123.45)))

Save a byte with \${}`and you can curry the function ton=>m=>...instead of(n,m)=>...`

Python 3 (207 159 110 95 86 bytes, thanks to @iwaseatenbyagrue)
A little bit of setup:
f = ['John', 'Jamie', 'Kylie', 'Laura', 'Russ', 'Karla', 'Reid', 'Mark', 'Manson', 'Lonnie', 'Nelly']
a = [100000, 0.05, 1549001.10, 999999999.99, 986000000, 1, 99.99, 999.99, 1000.01, 999999999999.00, -123.45]

My attempt:
['%s is in the %d-comma club.'%(p,-(-len(str(int(abs(v))))//3)-1) for p,v in zip(f,a)]

Results:
['John is in the 1-comma club.', 'Jamie is in the 0-comma club.', 'Kylie is in the 2-comma club.', 'Laura is in the 2-comma club.', 'Russ is in the 2-comma club.', 'Karla is in the 0-comma club.', 'Reid is in the 0-comma club.', 'Mark is in the 0-comma club.', 'Manson is in the 1-comma club.', 'Lonnie is in the 3-comma club.', 'Nelly is in the 0-comma club.']

Edit: converting everything to absolute values saved me 15 bytes.

Most importantly, this is a code snippet, Typically we only allow functions or full programs. As for golfing, You can remove many spaces. Try: ["%s is in the %d-comma club."%(p,v.count(','))for p,v in zip(f,a)] Also, you must include a byte count.

You can do print'\n'.join([your array]) and actually print output.

@ConorO'Brien Is there a better tag for this question? I am unfamiliar with bytes as a parsimony metric, but would go for number of characters instead.

@not_a_robot Bytes and characters are essentially equivalent, and bytes are preferred.

Welcome to the site! Negatives (e.g. -123.45) are off by one (since you count the -). But why not take a list of numbers and save (have I misinterpreted?). You'd need to add import statements, and as it stands this is a snippet not a program or function (as the defaults are, and changing from them is discouraged unless there is good reason).

Thanks, @JonathanAllan. I'm currently trying to improve this so I don't have to count the imports. I realize that Python's math.ceil function likely adds quite a bit of overhead to my score.

You can save 9 bytes by replacing (-len(str(abs(v)).split('.')[0]) with len(str(int(float(v)))).  In your test set, there are no negative numbers (in the examples, there is one). If you wanted to be completist, spend 5 bytes to do len(str(abs(int(float(v))))) - which then only saves you 4 bytes.

Python 2.7, 89 86 84 76 bytes
for g,b in input():print g,'is in the',`~-len('%d'%abs(b))/3`+'-comma club.'

Try it online!
Full program that takes a list of pairs of names and bank balances - and prints the resulting strings. (Note the question states "friends array and amounts array, but this is the format used by the accepted answer, so I guess it's allowed!)

Vim, 72 bytes
:%s;\v +\-=(\d+).*;\=' is in the '.(len(submatch(1))-1)/3.' comma club'

Somehow I should show that there's a trailing return, but unsure how.  This is just a basic regex answer, that I'm sure could be beaten by any regex language.  I would have used V, but I think that the substitute commands in V use / as a separator by default, and I couldn't figure out how to make it not complain about the divide.
Takes input as OP's table, and returns values as the table, but with the financial information replaced by " is in the X comma club"
Try it online!

I don't think the \-= adds anything. Also, if you remove the extra spaces in your input, and change the regex too \v (\d*).*; you could save 4 bytes

Python 2, 69 bytes
Setup our arrays:
n = ['John', 'Jamie', 'Kylie', 'Laura', 'Russ', 'Karla', 'Reid', 'Mark', 'Manson', 'Lonnie']
a = [100000, 0.05, 1549001.10, 999999999.99, 1000000000, 1, 99.99, 999.99, 1000.01, 999999999999.00]

And our function can then be:
f=lambda n,a:'%s is in %s comma club'%(n,min(3,(len(str(int(a)))/3)))

Giving us:
>>> [f(x,y) for x,y in zip(n,a)]
['John is in 2 comma club', 'Jamie is in 0 comma club', 'Kylie is in 2 comma club', 'Laura is in 3 comma club', 'Russ is in 3 comma club', 'Karla is in 0 comma club', 'Reid is in 0 comma club', 'Mark is in 1 comma club', 'Manson is in 1 comma club', 'Lonnie is in 3 comma club']

If the array needs to be identical to that provided in the question, then the solution costs 76 bytes:
f=lambda n,a:'%s is in %s comma club'%(n,min(3,(len(str(int(float(a))))/3)))

This does not take the arrays, but rather a single pair. Also, I don't think it caters for the negative number inputs as specified.

Powershell, 82 bytes
$args[0]|%{$_[0]+" is in the "+(('{0:N}'-f$_[1]-split',').Count-1)+"-comma club."}

Assuming a 2D-array input of
cc.ps1 @(@("John",100000),@("Jamie",0.05),@("Kylie",1549001.10),@("Laura",999999999.99),@("Russ",986000000),@("Karla",1),@("Reid",99.99),@("Mark",999.99),@("Manson",1000.01),@("Lonnie",999999999999.00),@("Nelly",-123.45))
The output is

John is in the 1-comma club.
Jamie is in the 0-comma club.
Kylie is in the 2-comma club.
Laura is in the 2-comma club.
Russ is in the 2-comma club.
Karla is in the 0-comma club.
Reid is in the 0-comma club.
Mark is in the 0-comma club.
Manson is in the 1-comma club.
Lonnie is in the 3-comma club.
Nelly is in the 0-comma club.

Haskell, 71 bytes
n#a=n++" is in the "++(show.truncate.logBase 1e3.abs$a)++"-comma club."

Defines an operator '#' that provides the correct answer.  E.g.:
*Main> "John"#100000
"John is in the 1-comma club."

Unfortunately, Haskell doesn't have a compact log10 function like many other languages, but it does have a useful logBase function, which means we don't need to divide our answer by 3.  Unfortunately, logBase 1000 0.05 is a negative number, so we need to use the longer truncate rather than floor to round it.
Full program including test cases:
(#) :: (RealFrac n, Floating n) => [Char] -> n -> [Char]
n#a=n++" is in the "++(show.truncate.logBase 1e3.abs$a)++"-comma club."

testCases = [
 ("John",      100000),
 ("Jamie",     0.05),
 ("Kylie",     1549001.10),
 ("Laura",     999999999.99),
 ("Russ",      986000000),
 ("Karla",     1),
 ("Reid",      99.99),
 ("Mark",      999.99),
 ("Manson",    1000.01),
 ("Lonnie",    999999999999.00),
 ("Nelly",     -123.45)]

main = putStrLn $ unlines $ map (uncurry (#)) testCases

Gives the following results:
John is in the 1-comma club.
Jamie is in the 0-comma club.
Kylie is in the 2-comma club.
Laura is in the 2-comma club.
Russ is in the 2-comma club.
Karla is in the 0-comma club.
Reid is in the 0-comma club.
Mark is in the 0-comma club.
Manson is in the 1-comma club.
Lonnie is in the 3-comma club.
Nelly is in the 0-comma club.

K, 66 bytes
    /n is names and a is amounts
    n
    ("John";"Jamie";"Kylie";"Laura";"Russ";"Karla";"Reid";"Mark";"Manson";"Lonnie")
    a
    ("100000";"0.05";"1549001.10";"999999999.99";"1000000000";,"1";"99.99";"999.99";"1000.01";"999999999999.00")
    /the function
    {x," is in the ",($(#.q.cut[3;*"."\:y])-1)," comma club"}./:+(n;a)
    /output
    ("John is in the 1 comma club";"Jamie is in the 0 comma club";"Kylie is in the 2 comma club";"Laura is in the 2 comma club";"Russ is in the 3 comma club";"Karla is in the 0 comma club";"Reid is in the 0 comma club";"Mark is in the 0 comma club";"Manson is in the 1 comma club";"Lonnie is in the 3 comma club")

C#, 125 bytes
(p,n)=>{for(int x=0;x<p.Length;x++)Console.Write(p[x]+" is in the "+(n[x]<1e3?0:n[x]<1e6?1:n[x]<1e9?2:3)+"-comma club.\n");};

Anonymous function which prints the result in the the OP's format.
Full program with test cases:
using System;

class CommaClub
{
    static void Main()
    {
        Action<string[], double[]> f =
        (p,n)=>{for(int x=0;x<p.Length;x++)Console.Write(p[x]+" is in the "+(n[x]<1e3?0:n[x]<1e6?1:n[x]<1e9?2:3)+"-comma club.\n");};

        // test cases:
        string[] personArr = new[] {"John", "Jamie", "Kylie", "Laura", "Russ", "Karla", "Reid", "Mark", "Manson", "Lonnie", "Nelly"};
        double[] amountArr = new[] {100000, 0.05, 1549001.10, 999999999.99, 1000000000, 1, 99.99, 999.99, 1000.01, 999999999999.00, -123.45};
        f(personArr, amountArr);
    }
}

Python 2, 87 bytes
for n,a in input():print n+' is in the %dd-comma club.'%'{:20,.2f}'.format(a).count(',')

Slightly older (90 bytes):
for n,a in input():print n+' is in the '+`'{:20,.2f}'.format(a).count(',')`+'-comma club.'

Takes input as a list of tuples (name, amount).
I'm doing this on my phone at school so I'll test it later.

Perl 6, 107 95 bytes
for @f {printf "%s is in the %d-comma club.\n",@f[$++],(abs(@a[$++].split(".")[0]).chars-1)/3;}

Not my proudest work, give me a heads up if ive forgotten any golfing techniques.
EDIT: -12 bytes thanks to @Ven

why parens around ^@f.elems? btw you don't need that .elems, for ^@f works. You don't need to name your $x, use $_ instead. And don't use printf, use "{"interpolation"}".

I don't even understand why you need that. Why not go for for @f? You can use $++ as an index to go along with it (and index into @a).

ill edit as soon as im on the pc :)

@Ven thanks for the heads up about the $++. Saves me alot of trouble in my "real" programs. Just picked up Perl 6.

Are you sure interpolations don't save bytes?

That @f[$++] can be $_, as said in my first comment. However you probably want to for @a so you can write abs(.split…) (and keep @f[$++])

Swift, 166 158 145 bytes
var c="comma club",i=0
f.map{k,v in var a=abs(v);print(k,(1000..<1000000~=a ?1:1000000..<1000000000~=a ?2:1000000000..<1000000000000~=a ?3:0),c)}

And here is the dictionary:
var f = [
    "John": 100000, "Jamie": 0.05, "Kylie" : 1549001.10,
    "Laura": 999999999.99,"Russ":1000000000,"Karla": 1,
    "Reid": 99.99,"Mark": 999.99, "Manson": 1000.01,
    "Lonnie": 999999999999.00, "Nelly": -123.45
]

Try it here!

dc, 56 54 bytes
[P[ is in the ]Pd*vdZrX-1-3/n[-comma club.]pstz0<g]sglgx

This takes input from the stack, which should be pre-loaded with the first name at top of stack, the first number, the second name, second number, etc.
Here is an example of loading the stack and running the macro, g:
#!/usr/bin/dc
_123.45         [Nelly]
999999999999.00 [Lonnie]
1000.01         [Manson]
999.99          [Mark]
99.99           [Reid]
1               [Karla]
986000000       [Russ]
999999999.99    [Laura]
1549001.10      [Kylie]
0.05            [Jamie]
100000          [John]
[P[ is in the ]Pd*v1/Z1-3/n[-comma club.]pstz0<g]sglgx

which produces the usual output,
John is in the 1-comma club.
Jamie is in the 0-comma club.
Kylie is in the 2-comma club.
Laura is in the 2-comma club.
Russ is in the 2-comma club.
Karla is in the 0-comma club.
Reid is in the 0-comma club.
Mark is in the 0-comma club.
Manson is in the 1-comma club.
Lonnie is in the 3-comma club.
Nelly is in the 0-comma club.

Here's an exegesis of the code:
[P[ is in the ]Pd*v1/Z-1-3/n[-comma club.]pstz0<g]sglgx

[                    # begin macro string
P                    # print and pop person name
[ is in the ]P       # print and pop ' is in the '
# Get absolute value of number by squaring and square root
d*v                  # d=dup, *=multiply, v=root
1/                   # 1/ truncates to integer since scale is 0
Z                    # Z=number length
1-3/n                # n=print and pop (#digits - 1)//3
[-comma club.]p      # print '-comma club.' and newline
st                   # pop '-comma club.' off stack into register t
z0<g                 # Do macro g if 0 is less than z=stack height
]                    # end macro string
sg                   # Save macro g
lgx                  # Load g and do its initial execution

Note, in edit 1 I replaced dZrX- (d=dup, Z=number length, r=swap, X=fraction, -=subtract) with 1/Z (divide number by 1, which with default scale of zero truncates to integer; then Z=number length), saving two bytes.

Vyxal, 29 bytes
¹ð«E⟨b?6Ḃ«⁰²∆τ6ḭS‹`ḊṄa ⟇¦.`Wṅ

Try it Online!
Explained
¹ð«E⟨b?6Ḃ«⁰²∆τ6ḭS‹`ḊṄa ⟇¦.`Wṅ
¹ð                             # Get first input and push space
  «E⟨b?6Ḃ«                     # Push compressed string "is in the "
          ⁰²                   # Get second input and square it
            ∆τ                 # Log10 it
              6ḭ               # Floor divide by 6
                S              # Stringify
                 ‹             # Push a hyphen
                  `ḊṄa ⟇¦.`    # Push string "comma club"
                           Wṅ  # Join stack

JavaScript (V8), 55 bytes
n=>m=>n+` is in the ${Math.log10(m*m)/6|0}-comma club.`

Try it online!

Java 8 154 141 bytes
m.keySet().stream().map(k->k+" is in the "+(((""+Math.abs(m.get(k).longValue()))).length()-1)/3+"-comma club.").forEach(System.out::println);

Ungolfed
public static void main(String[] args) {
    Map<String, Number> m = new LinkedHashMap<String, Number>(){{
        put("John", 100000);
        put("Jamie", 0.05);
        put("Kylie", 1549001.10);
        put("Laura", 999999999.99);
        put("Russ", 1000000000);
        put("Karla", 1);
        put("Reid", 99.99);
        put("Mark", 999.99);
        put("Manson", 1000.01);
        put("Lonnie", 999999999999.00);
        put("Nelly", -123.45);
    }};
    m.keySet().stream().map(k->k+" is in the "+(((""+Math.abs(m.get(k).longValue()))).length()-1)/3+"-comma club.").forEach(System.out::println);
}

You can remove the String.valueOf and use (((""+Math.abs(m.get(k).longValue())).length()-1)/3) instead.

And you can also remove the parenthesis around k->.

Clojure, 108 bytes
(def f ["John", "Jamie", "Kylie", "Laura", "Russ", "Karla", "Reid", "Mark", "Manson", "Lonnie", "Nelly"])
(def a ["100000", "0.05", "1549001.10", "999999999.99", "986000000", "1", "99.99", "999.99", "1000.01", "999999999999.00", "-123.45"])

(map #(str %" is in the "(quot(-(count(nth(partition-by #{\.}(drop-while #{\-}%2))0))1)3)"-comma club.")f a)

Not sure if operating on floats would be shorted than on sequences of characters. Not sure if non-function answer is fine which returns a sequence of answers.

Rebol, 118 bytes
d: charset"0123456789"forskip s 2[c: 0 parse s/2[opt"-"any[3 d and d(++ c)]]print[s/1"is in the"join c"-comma club."]]

Ungolfed with array declaration:
s: [
    {John} {100000}
    {Jamie} {0.05}
    {Kylie} {1549001.10}
    {Laura} {999999999.99}
    {Russ} {986000000}
    {Karla} {1}
    {Reid} {99.99}
    {Mark} {999.99}
    {Manson} {1000.01}
    {Lonnie} {999999999999.00}
    {Nelly} {-123.45}
    {Baz} {1.12345678}     ;; added extra Baz test case
]

d: charset "0123456789"
forskip s 2 [
    c: 0
    parse s/2 [
        opt "-"
        any [3 d and d (++ c)]
    ]
    print [s/1 "is in the" join c "-comma club."]
]

Output:
John is in the 1-comma club.
Jamie is in the 0-comma club.
Kylie is in the 2-comma club.
Laura is in the 2-comma club.
Russ is in the 2-comma club.
Karla is in the 0-comma club.
Reid is in the 0-comma club.
Mark is in the 0-comma club.
Manson is in the 1-comma club.
Lonnie is in the 3-comma club.
Nelly is in the 0-comma club.
Baz is in the 0-comma club.

Factor, 52 bytes
[ sq log10 6 /i [I ${} is in the ${}-comma club.I] ]

Attempt This Online!
Port of @MatthewJensen's JavaScript answer.

doesn't work for me... could you get a working ATO/TIO link?

@Steffan I had no idea about ATO. It uses a later build than TIO so [I works. The problem is that mnapply is bugged in that build. Try this.


text:
Happy Birthday V!
Thanks to @KritixiLithos for helping me out with this challenge!

V is a programming language that I wrote so that I could use and extend vim for code-golf challenges. The very first commit was on March 3rd, 2016, meaning that today V turns one year old! Woo-hoo
Over V's first year of existence, there have been 176 commits from four different contributors, 140 answers from 12 different users, and too many broken duplicate operators to count. It has an online interpreter, generously hosted by @Dennis, which has been run almost 8,000 times since December.
Let's have a challenge to celebrate V's birthday! Since most features in V are designed with string manipulation and ascii-art in mind, it just seems natural that any challenge celebrating V should be about ascii art. So your challenge for today is to take a word as input, and reshape that word in the shape of a V. For example, the input "Hello" should give the following V:
Hello         olleH
 Hello       olleH
  Hello     olleH
   Hello   olleH
    Hello olleH
     HellolleH
      HellleH
       HeleH
        HeH
         H

Here are some details about what your V should look like. If the input string is n characters long, the V should be n*2 lines tall. The very first line should consist of:
<input string><(n*2) - 1 spaces><input string reversed>

On each new line, one space is added to the beginning, and the two sides of the string move towards each other, removing any overlapping characters. Until the very last line, which is just the first character of input. Trailing whitespace on each line is acceptable, and a trailing newline is allowed too.
You can assume that the input will always be printable ASCII without any whitespace in it, and you may take input and output in any reasonable method. Here are some more sample inputs:
Happy:

Happy         yppaH
 Happy       yppaH
  Happy     yppaH
   Happy   yppaH
    Happy yppaH
     HappyppaH
      HapppaH
       HapaH
        HaH
         H

Birthday:

Birthday               yadhtriB
 Birthday             yadhtriB
  Birthday           yadhtriB
   Birthday         yadhtriB
    Birthday       yadhtriB
     Birthday     yadhtriB
      Birthday   yadhtriB
       Birthday yadhtriB
        BirthdayadhtriB
         BirthdadhtriB
          BirthdhtriB
           BirthtriB
            BirtriB
             BiriB
              BiB
               B

V!:

V!   !V
 V! !V
  V!V
   V

~:

~ ~
 ~

Of course, since this is code-golf, standard loopholes are banned and your goal is to write the shortest possible program to complete this task. Happy golfing!

For what it's worth, I have a soft spot for vim answers, so imaginary bonus points for using vim or V, although any language is acceptable. :)

Can I print a single null character (0x00) after every newline?

@wheatwizard Hmm. It's a little weird, but I guess that's fine as long as the output is visually same.

The 5th birthday will be something else! (In roman numerals)

Best wishes to the V language by the Vee :-)

MATL, 21 14  bytes
MATL wishes V a happy birthday!
tnEXyY+c3MZvZ)

Try it online!
Explanation
Consider the input
'Hello'

of length n=5. The code computes the 2D convolution of this string with the identity matrix of size 2*n,
[1 0 0 0 0 0 0 0 0 0;
 0 1 0 0 0 0 0 0 0 0;
 0 0 1 0 0 0 0 0 0 0;
 0 0 0 1 0 0 0 0 0 0;
 0 0 0 0 1 0 0 0 0 0;
 0 0 0 0 0 1 0 0 0 0;
 0 0 0 0 0 0 1 0 0 0;
 0 0 0 0 0 0 0 1 0 0;
 0 0 0 0 0 0 0 0 1 0;
 0 0 0 0 0 0 0 0 0 1]

The result of the convolution, converted to char and with char 0 shown as space, is
['Hello         ';
 ' Hello        ';
 '  Hello       ';
 '   Hello      ';
 '    Hello     ';
 '     Hello    ';
 '      Hello   ';
 '       Hello  ';
 '        Hello ';
 '         Hello']

Then the columns [1, 2, ..., 2*n-1, 2*n, 2*n-1, ..., 2, 1] are selected from this char matrix, producing the desired result:
['Hello         olleH';
 ' Hello       olleH ';
 '  Hello     olleH  ';
 '   Hello   olleH   ';
 '    Hello olleH    ';
 '     HellolleH     ';
 '      HellleH      ';
 '       HeleH       ';
 '        HeH        ';
 '         H         ']

Commented code
t      % Implicitly input string. Duplicate
nE     % Length, say n. Multiply by 2
Xy     % Identity matrix of that size
Y+     % 2D convolution. This converts chars to ASCII codes
c      % Convert to char
3M     % Push 2*n, again
Zv     % Push symmetric range [1, 2, ..., 2*n, 2*n-1, ..., 1]
Z)     % Apply as column indices. This reflects the first 2*n columns
       % symmetrically, and removes the rest. Implicitly display

Very interesting approach! +1

@seshoumara Thanks! As flawr says, convolution is the key to success :-)

V, 24, 23, 20 bytes
3Ù2Ò Íî
Xæ$òâÙHãêxx>

Try it online!
Much shorter now that V has a 'reverse' operator.
Not that impressive compared to the other golfing languages that have answered, but it had to be done. Hexdump:
00000000: 33d9 32d2 20cd ee0a 58e6 24f2 e2d9 48e3  3.2. ...X.$...H.
00000010: ea78 783e                                .xx>

Explanation:
3Ù                  " Make three extra copies of this current line
  2Ò                " Replace each character on this line and the next line with spaces
     Íî             " Join all lines together
X                   " Delete one space
 æ$                 " Reverse the word under the cursor

At this point, the buffer looks like this:
Happy         yppaH

No, we'll recursively build the triangle down.
ò                   " Recursively:
 â                  "   Break if there is only one non-whitespace character on this line
  Ù                 "   Make a copy of this line
   H                "   Move to the first line
    ã               "   Move to the center of this line
     ê              "   Move to this column on the last line
      xx            "   Delete two characters
        >           "   Indent this line

Here is where I get to show off one of my favorite features of V. Lots of commands require an argument. For example, the > command will indent a variable number of lines depending on the argument:
>>    " Indent this line (this command is actually a synonym for '>_')
>j    " Indent this line and the line below
>k    " Indent this line and the line above
6>>   " Indent 6 lines
>}    " Indent to the end of this paragraph
>G    " Indent to the last line
...   " Many many many more

but most commands will be forced to end with a default argument (usually the current line) if it is at the end of the program and not specified. For example, what V actually runs for our recursive loop is:
òâÙHãêxx>>ò

The second ò is implicitly filled in. The cool thing is that implicitly ended commands apply several layers deep, so even though we only wrote >, V will implicitly give _ for it's argument, and it will indent the current line.

I was working on it, but I think it's more fitting for you to answer!

Brainfuck, 152 bytes
This is such a momentous occasion, I decided to crack out the ol' BF interpreter and give this a spin.
++++++++++[->+>+++<<]>>++>>+>>>,[[<]<<+>>>[>],]<[<]<<-[->+>>[>]>++++[-<++++++++>]<[<]<<]>[->++<]>[-<+>]<[<[-<+<.>>]<[->+<]>+>->>[.>]<[-]<[.<]<<<<<.>>>>]

With Comments
++++++++++
[->+>+++<<] Insert 0 into the first buffer (Which we don't care about) 10 into the second and 30 into the thrd
>>++    Raise the third buffer to 32 making us our space
>   This buffer is reserved for the Insertable spaces counter
>
+>>>    Raise our incrementer This will be used to fill the other half of the string with spaces
,[  Read a byte
    [<]<<   Move to the back of the string buffer which is our incrementer
    +       increment it
    >>>[>]      And move to the next space of the string
    ,       And then read a new byte
]
<[<]<<-     Decrement the incrementer and begin to add spaces
[
    -       Decrement the incrementer
    >+      Raise the incrementer in the padding
    >>[>]   Move to a new part of the string buffer
    >++++[-<++++++++>]< Write a space
    [<]<<   Move all the way back to the string counter
]
BEGIN WRITING!!
>
[->++<]>[-<+>]<Double the incrementer
[
    <[  Move to the space counter
        -<+<.>> Decrement the space counter increment the temporary one to the left of it then print the space we stored to the left of that then return
    ]<[->+<]>+> Move the temporary space counter back
    -   Decrement the incrementer
    >>[.>]  Print every character from left to right
    <[-]    Snip the end off this
    <[.<]   Print every character from right to left
    <   Move back ot the incrementer
    <<<<.>>>> Print a newline aswell
]

Try it online!

><>, 221 bytes
I spent way too much time on this. Happy birthday, V!
l:2*01           p84*/v
 !@:$-1         /!?:$<
  1.v/ ^       v\~~>a
   vv\}o<     >ao  /
    1\/84/   :}o:$-
     \\!?<: l;!?\v
      p10-1:g10r\
       >  :>?\vv
        v:$-1/~
         </r+*
          </~
           l

You can try it online, but it's a lot more fun to get this interpreter and run it using the --play flag
python3 fish.py v.fish -s "ppcg" --tick 0.05 --play

which results in the animation below.
Example

(it takes a little under two minutes)
Explanation
Because the interesting part of this answer is wrapping it in the V shape, here is an explanation that conforms to it.  We use following line-numbered version for reference.
1. l:2*01           p84*/v
2.  !@:$-1         /!?:$<
3.   1.v/ ^       v\~~>a
4.    vv\}o<     >ao  /
5.     1\/84/   :}o:$-
6.      \\!?<: l;!?\v
7.       p10-1:g10r\
8.        >  :>?\vv
9.         v:$-1/~
10.         </r+*
11.          </~
12.           l

Sometimes arrows (→↓←) are used to indicate the direction in which a snippet is reached.

Initialisation
   1.→l:2*01           p84*/v
   2.  !@:$-1   X     /!?:$<
   3.   1.            \~~>a

The first line will push 2n to [0,1], leave n on the stack and append one space. Next, we go up and wrap around to the second line on the right, where we will start going left. There is a loop for appending n + 1 spaces. This works as follows.
                Initial:                 "ppcg4 "
!@:$-1 /!?:$<
           $     Swap.                   "ppcg 4"
          :      Duplicate.              "ppcg 44"
         ?       If more spaces to add:
    -1            Subtract 1.            "ppcg 3"
   $              Swap.                  "ppcg3 "
  :               Duplicate.             "ppcg3  "
 @                Rotate top 3.          "ppcg 3 "
!                 Jump over stored value
                         and wrap around.
                Else:
        /         Go to next part.

After this is finished, it bounces down to line 3. There the top two stack elements (0 and a space) are removed (~~) and we jump to the X at location [10,1] (a1.), continuing rightwards. We bump up at the /, wrap around to line 7 and start the main program loop.
Main loop (2n times do)
 6.              ;!?\
 7.       p10-1:g10r\   ←

This is the loop condition. At first, the stack is reversed for printing. Then we get the counter from [1,0] (01g) and store a decremented version (:1-01p). By wrapping around and bumping up and right, we encounter the conditional for terminating the program. If we don't terminate, we jump into the first printing loop.

First printing loop (left half)
5.    1\   /   :}o:$-
6.     \\!?<: l         ←

We start with the length on top of the stack and execute the following code as long as the top element is not 0.
1-$:o}

1-        Subtract 1.    "ppcg3"
  $       Swap.          "ppc3g"
   :      Duplicate.     "ppc3gg"
    o     Output.        "ppc3g"
     }    Rotate right.  "gppc3"

This will print the stack without discarding it. If the loop terminates, we jump to the right on line 5, preparing for the next printing loop.
Preparation of right half
5.  →    /84/
6.       \
7.            :
8.            >
9.         v:$-1/~
10.         </r+*
11.          </~
12.           l

This was one of the hardest parts to fit. Below is a version stripped of all direction wrapping to indicate what happens.
             Initial stack:   "    gcpp0"
84*+r~
84*          Push 32 == " ".  "    gcpp0 "
   +         Add 32 and 0.    "    gcpp "
    r        Reverse.         " gcpp    "
     ~       Remove top.      " gcpp   "

We then push the length of what is to be printed and start the second printing loop (with an initial duplicate not part of the loop).
Second printing loop (right half)
3.     / ^
4.     \}o<
5.
6.           ↓
7.
8.       >  :>?\vv
9.        v:$-1/~

The code being executed is completely the same as in the first printing loop, with the o} being placed a bit further because there were available locations. Upon finishing, we have a few things left to do before we can verify the main loop invariant again. After the ~ on line 9 is executed we wrap around vertically, ending up at the following piece of code.
                ↓
2.          X     /
3.  1.v/             >a
4.              >ao  /

First ao will print a newline. Then we bounce up and arrive at exactly the same spot from after the initialisation, namely jumping to the X.

you should probably make the golfed version the main version

@DestructibleWatermelon the post is more about the V version though, as it was much harder to mold everything in a specific shape with only a limited number of available bytes. Explanation will therefore follow for the V version, rather than the plain one. I might make an actually golfed one later.

This is gold just gold

I appreciate that this answer is in a language whose name consists exclusively of rotated 'V's.

Brain-Flak, 486 + 1 = 489 bytes
Happy Birthday V from Brain-Flak!
Also a Thank you to 0                                                                                ' who provided some of the code used in this answer
+1 due to the -c flag which is required for ASCII in and out
((([]<{({}<>)<>}<>([]){({}[()]<(([][()])<{({}[()]<({}<>)<>>)}{}><>)<>({}<<>{({}[()]<({}<>)<>>)}{}><>)(({})<>)<>>)}{}([][][()]){({}[()]<((((()()()()){}){}){})>)}{}<>{({}<>)<>}<>>){}[()])<{((({})<((({}){}())){({}[()]<(({}<(({})<>)<>>)<(({}<({}<>)<>>[()])<<>({}<<>{({}[()]<({}<>)<>>)}{}>)<>>){({}[()]<({}<>)<>>)}{}<>>)>)}{}{}((()()()()()){})(<()>)<>>)<{({}[()]<({}<>)<>>)}{}{}{}{({}<>)<>}<>>[()])}{}>()())([][()]){{}(({}[()])<{({}[()]<((((()()()()){}){}){})>)}{}{({}<>)<>}{}>)([][()])}{}<>

Try it online!
This is without a doubt the hardest thing I have ever done in Brain-Flak.
Brain-Flak is notoriously terrible at duplicating and reversing strings and this challenge consists of nothing but duplicating and reversing strings.
I managed to get this almost working snippet in just under an hour of hard work, but adding in the last few spaces turned out to be one of the most difficult things I have ever done in Brain-Flak.
Explanation
The basic Idea is that we will create the top of the V first and each iteration remove two characters from the middle and add a space to the beginning.
In practice this becomes quite difficult.
Existing algorithms exist for copy and reverse so I used one of those to create a reversed copy of the code on the offstack.  Once I've done that I put 2n-1 spaces on top of the original stack and move the offstack back onto the onstack to create a sandwich.

Now we have our top row.  Now we want to remove two characters from the beginning and add a space to the front.  This turns out to be the most difficult part.  The reason for this is that we need to essentially store two values, one for the depth of the current snippet and one for the depth to the center of the V where the deletion has to occur.
This is hard.
Because of all the duplication and reversal that is going on both of the stacks are in full use all of the time.  There really is nowhere on these stacks to put anything.  Even with all of the Third Stack Magic in the world you can't get the type of access you need to solve this problem.
So how do we fix it?  In short we don't really; we ignore the spaces for now and patch them in later we will add zeros to the code to mark where the spaces are intended to go but other than that we won't really do anything.
So on each iteration we make a copy of the last iteration and put it onto the offstack.  We use the depth we stored to split this in half so we have the left half of the V on the right stack and the right half of the V on the left stack.  We remove two elements and patch the two back together.  We add a newline for good measure and start the next iteration.  Each time the depth to the center of the V decreases by one and when it hits zero we stop the loop.
Now we have the bulk of the V constructed.  We are however lacking proper spaces and our V is currently a bit (read: completely) upside-down.

So we flip it.  To flip it onto the other stack we have to move each element over one by one.  As we are moving elements we check for zeros.  If we encounter one we have to put the spaces back in where they belong.  We chuck the zero and add in a bunch of spaces.  How do we know how many?  We keep track; flipping a stack unlike duplicating or reversing one is a very un-intensive task so we actually have the memory to store and access an additional counter to keep track of how many spaces to add.  Each time we add some spaces we decrement the counter by one.  The counter should hit zero at the last newline (the top of the V) and thus we are ready to print.
Lastly we clean up a few things hanging around and terminate the program for implicit output.

Very impressive that you managed to get it working at all! Do you think you could save bytes by leaving it reversed and adding the -r flag?

@DJMcMayhem I don't think so.  The reversal process and the insertion of spaces happen at the same time, so if I added the -r flag I would need to actually reverse it another time.  It is getting to be late where I am but I think I will work on trying to golf this down substantially tomorrow.  If I can fix the spaces problem I will definitely use the -r flag.

Python 3, 65 bytes
s=input();s+=' '*len(s)
for _ in s:s=' '+s[print(s+s[-2::-1]):-1]

Try it online!

Python 2, 65 bytes
s=input();s+=' '*len(s)
for _ in s:print s+s[-2::-1];s=' '+s[:-1]

Try it online!

Jelly, 15 12 bytes
⁶ṁ⁸;;\Uz⁶ŒBY

Try it online!
How it works
⁶ṁ⁸;;\Uz⁶ŒBY  Main link. Argument: s (string)

⁶ṁ            Mold ' ' like s, creating a string of len(s) spaces.
  ⁸;          Prepend s to the spaces.
    ;\        Cumulative concatenation, generating all prefixes.
      U       Upend; reverse each prefix.
       z⁶     Zip/transpose, filling empty spots with spaces.
         ŒB   Bounce; map each string t to t[:-1]+t[::-1].
           Y  Join, separating by linefeeds.

It is 12 characters, but is there any encoding where it would come out as just 12 bytes?

Yes, Jelly uses it own custom code page.

JavaScript (ES6), 108 106 98 94 bytes

f=
s=>s.repeat((j=l=s.length*4)*2).replace(/./g,_=>--j?s[j+j<l?j-i:l-i-j]||` `:(j=l,++i,`
`),i=1)
<input oninput=o.textContent=f(this.value)><pre id=o>

Would you be able to make a post explaining this? I'm a bit confused by the replacement, and regular expressions.

@JacobPersi They're a red herring. All I need is an output area of size n*2 by n*4 (including the newlines at the end of each line). I then calculate the character that should appear in each cell.

Nice! You can shave off a byte by removing the newline between f= and s=>.

@yummypasta The f= is only part of the snippet, not the answer. As such, it isn't included in the byte count.

Retina, 51 47 bytes
Happy birthday from a fellow string-processing language!
Byte count assumes ISO 8859-1 encoding.
$
$.`$*
$
¶$`
O$^r`.\G

;{*`.¶

(\S.*).¶.
 $1¶

Try it online!
Explanation
$
$.`$*

This appends n spaces (where n is the string length), by matching the end of the string, retrieving the length of the string with $.`, and repeating a space that many times with $*.
$
¶$`

We duplicate the entire string (separated by a linefeed), by matching the end of the string again and inserting the string itself with $`.
O$^r`.\G

This reverses the second line by matching from right-to-left (r), then matching one character at a time (.) but making sure that they're all adjacent (\G). This way, the matches can't get past the linefeed. This is then used in a sort-stage. By using the sort-by mode ($) but replacing each match with an empty string, no actual sorting is done. But due to the ^ option, the matches are reversed at the end, reversing the entire second line.
;{*`.¶

This stage is for output and also affects the rest of the program. { wraps the remaining stages in a loop which is repeated until those stages fail to change the string (which will happen because the last stage won't match any more). The ; disables output at the end of the program. The * turns this stage into a dry-run which means that the stage is processed and the result is printed, but afterwards the previous string is restored.
The stage itself simply removes a linefeed and the preceding character. Which gives us one line of the desired output (starting with the first line).
(\S.*).¶.
 $1¶

Finally, this stage turns each line into the next. This is done by inserting a space in front of the first non-space character, removing the last character on the first line, as well as the first character on the second line. This process stops once there is only one non-space character left on the first line, which corresponds to the last line of the output.

Would love an explanation of how this works. I know sed's syntax is less compact, but my draft is twice longer. Reversing string and putting together the first output line is most of it.

@seshoumara Sure, there you go.

Thanks. Now I know a double length sed script is not bad :)) due to extra s/// chars that add up, to lengthier string reversal and other operations that lack the niceties of Retina. Good read. +1

Japt, 22 20 16 14 + 2 bytes
Japt wishes V many more successful years of golfing!
²¬£²îU²ç iYU)ê

Requires the -R flag. Test it online!
Explanation
This makes use of the ç and î functions I added a few days ago:
²¬£²îU²ç iYU)ê    Implicit: U = input string
²                 Double the input string.
 ¬                Split into chars.
  £               Map each char X and index Y by this function:
     U²             Take the input doubled.
       ç            Fill this with spaces.
         iYU        Insert the input at index Y.
    î       )       Mask: repeat that string until it reaches the length of
   ²                the input doubled.
                    This grabs the first U.length * 2 chars of the string.
             ê      Bounce the result ("abc" -> "abcba").
                  Implicit: output result of last expression, joined by newlines (-R flag)

Dennis's technique is a byte longer:
U+Uç)å+ mw y mê

05AB1E, 12 bytes
Dgð×J.p€ûR.c

Try it online!
Explanation
D             # duplicate input
 g            # length of copy
  ð×J         # append that many spaces to input
     .p       # get a list of all prefixes
       €û     # turn each into a palindrome
         R    # reverse the list
          .c  # pad each line until centered

Or for the same byte count from the other direction.
Âsgú.sí€ûR.c

Explanation
Â             # push a reversed copy of input
 s            # swap the input to the top of the stack
  g           # get its length
   ú          # prepend that many spaces
    .s        # get a list of all suffixes
      í       # reverse each
       €û     # turn each into a palindrome
         R    # reverse the list
          .c  # pad each line until centered

If you indent the comments incrementally, then even the source looks like a V :)

GNU sed, 110 100 + 1(r flag) = 101 bytes
Edit: 9 bytes shorter thanks to Riley
As another string manipulation language, sed wishes V the best!
h;G
:;s:\n.: \n:;t
h;:r;s:(.)(\n.*):\2\1:;tr
H;x
s:\n\n ::
:V
h;s:\n::p;g
s:^: :;s:.\n.:\n:
/\n$/!tV

Try it online!
Explanation: assuming the input is the last test case ('V!'). I will show the pattern space at each step for clarity, replacing spaces with 'S's.
h;G                       # duplicate input to 2nd line: V!\nV!
:;s:\n.: \n:;t            # shift each char from 2nd line to 1st, as space: V!SS\n
h;:r;s:(.)(\n.*):\2\1:;tr # save pattern space, then loop to reverse it: \nSS!V
H;x                       # append reversed pattern to the one saved V!SS\n\n\nSS!V
s:\n\n ::                 # convert to format, use \n as side delimiter: V!SS\nS!V
:V                        # start loop 'V', that generates the remaining output
h;s:\n::p;g               # temporarily remove the side delimiter and print pattern
s:^: :;s:.\n.:\n:         # prepend space, delete char around both sides: SV!S\n!V
/\n$/!tV                  # repeat, till no char is left on the right side
                          # implicit printing of pattern left (last output line)

Python, 110 bytes
Try it online!
I'm sure this isn't optimal, but it's pretty Pythonic at least:
def f(s):n=len(s)*2-1;return''.join(i*' '+s[:n+1-i]+(n-2*i)*' '+s[n-i-1::-1]+'\n'for i in range(n))+n*' '+s[0]

Batch, 186 185 bytes
@set e=@set
%e%/ps=
%e%t=%s%
%e%r=
:l
%e%s=%s%
%e%r= %r%%t:~-1%
%e%t=%t:~,-1%
@if not "%t%"=="" goto l
:g
%e%r=%r:~1%
@echo %s%%r%
%e%s= %s:~,-1%
@if not "%r%"=="" goto g

Lines 1 and 6 have a trailing space. Edit: Saved 1 byte thanks to @ConorO'Brien.

Here's a convoluted way to save a byte. (create an alias for @set  and remove @echo off, inserting @ as necessary.

@ConorO'Brien Thanks, I'd never have guessed that 8 sets would have saved me enough bytes to make it worthwhile.

Jolf, 31 bytes
Jolf begrudgingly wishes V a happy birthday!
RΜwzΒώlid+γ_pq_ l+*␅Hi0ΒΒ␅ L_γ1S

Try it here! ␅ should be 0x05.
Explanation
RΜzΒώlid+γ_pq_ l+*␅Hi0ΒΒ␅ L_γ1S  i = input
     li                                  i.length
    ώ                                2 *
   Β                             Β =
  z                              range(1, Β + 1)
 Μ     d                         map with: (S = index, from 0)
                +                 add:
                 *␅H               S spaces
                    i              and the input
               l                  slice (^) from
                     0Β            0 to Β
           pq_         Β␅         pad (^) with spaces to the right
         γ_                       γ = reverse (^)
        +                 L_γ1    γ + behead(γ)
R                             S  join with newlines

Charcoal, 29 bytes
Happy birthday V, from your fellow disappointingly-long-for-this-challenge ASCII-art language!
ＳσＦ…·¹Ｌσ«Ｆι§σκＭι←↖»Ｆσ«Ｐσ↖»‖Ｏ→

Try it online!
Explanation
Our strategy: print the left half of the V, starting from the bottom and moving to the upper left; then reflect it.
Ｓσ                                    Input σ as string
                                       The bottom len(σ) half-rows:
   Ｆ…·¹Ｌσ«           »               For ι in inclusive range from 1 to length(σ):
            Ｆι                          For κ in range(ι):
               §σκ                         Print character of σ at index κ
                  Ｍι←                   Move cursor ι spaces leftward
                      ↖                  Move cursor one space up and left
                                       The top len(σ) half-rows:
                        Ｆσ«    »      For each character ι in σ:
                            Ｐσ          Print σ without moving the cursor
                               ↖         Move cursor one space up and left
                                 ‖Ｏ→  Reflect the whole thing rightward, with overlap

(If only Charcoal had string slicing... alas, it appears that hasn't been implemented yet.)

Although Charcoal didn't have string slicing, it did have CycleChop, which can be used to extract the head of the string, thus saving 4 bytes. However, there is a better approach which saves 9 bytes. Some more savings which I think also worked at the time: Reflect defaults to a right reflect, saving a further byte, and one of the variables is predefined to the first input, saving two bytes.

Pip, 32 25 bytes
a.:sX#aL#a{OaDQaPRVaaPUs}

Takes the input string as a command-line argument. Try it online!
Explanation
                           a is 1st cmdline arg, s is space (implicit)
     #a                    Len(a)
   sX                      Space, string-multiplied by the above
a.:                        Concatenate that to the end of a
       L#a{             }  Loop len(a) times (but NB, a is now twice as long as it was):
           Oa                Output a (no trailing newline)
             DQa             Dequeue one character from the end of a
                PRVa         Print reverse(a) (with trailing newline)
                    aPUs     Push one space to the front of a

R with stringi package, 225 Bytes
library(stringi)
f=function(){
s=scan(,'',1,sep="\n")
m=2*nchar(s)
l=stri_pad(sapply(1:m-1,function(x)substr(paste(paste(rep(" ",x),collapse=""),s),1,m)),m,"right")
r=substr(stri_reverse(l),2,m)
message(paste0(l,r,"\n"))}
f()

If you run R in interactive code, after pasting my answer just input anything.
You will need the stringi R package to be installed (I hope it's not against the rules).
Explanation:
The basic idea is to add spaces to the left side, then cut it to the right length. After that, paste it with its reversed version as the right side. Here is a longer, human-readable version of the function:
library(stringi)
make_V <- function(){                  # declaring the function
  string <- scan(, '', n=1, sep="\n")  # reading input
  max_length <- 2*nchar(string)        # number of chars in each half row

  # creating the left side of the V

  left <- stri_pad(
            sapply(1:max_length-1,     # for each row
                   function(x){
                    substr(
                      paste0(
                        paste0(rep(" ", x),
                               collapse=""), string), # add spaces to left side
                           1,
                           max_length) # cut the unneeded end
                    }),
            width=max_length,
            side="right")              # add spaces to the right side

  # creating the right side of the V

  right <- substr(stri_reverse(left), 2, max_length)

  # print it without any symbols before the strings
  message(paste0(left, right, "\n"))
}

# run the function
make_V()

Welcome to the site! :)

Ruby, 92 89 85 bytes
s=gets.chomp
s<<" "*n=s.size*2
n.times{s=s[0..(n-1)]
puts s+s.reverse[1..-1]
s=" "+s}

My process was to remove the first character from the right half of each line after reversing the first half.
Like this:
Hello     |    olleH
 Hello    |   olleH
  Hello   |  olleH
   Hello  | olleH
    Hello |olleH
     Hello|lleH
      Hell|leH
       Hel|eH
        He|H
         H|

I'm not used to trying to golf things so let me know if there's anything I can do to get it shorter.

Welcome to the site, this is a nice answer! Unfortunately, I really don't know a whole lot about ruby, so I can't offer any tips. You might be able to find something on this page though.

Thanks! There are a lot of interesting things on that page but I seem to already be doing a lot of them.  I did realize I could save some bytes via side-effects and order of operations though.

I assume [Ruby] is just Ruby, the more-or-less well-known programmign language?

You can save 8 bytes by making this a lambda.

Haskell, 76 bytes
v is the main function, taking a String argument and giving a String result.
v i=unlines.r$i++(' '<$i)
r""=[]
r s|t<-init s=(s++reverse t):map(' ':)(r t)

Try it online!
Notes:

i is the initial argument/input.
s is initially i with length i spaces appended.
v i calls r s, then joins the result lines.
r returns a list of String lines.
t is s with the last character chopped off.
The recursion r t produces the lines except the first, minus the initial space on each line.

+1 for naming the main function v. :D

@DJMcMayhem: not naming the main function is one byte longer: unlines.r.((++)<*>(' '<$)).

@nimi I assume he liked which name I chose. Technically a lambda ties... When I wrote the answer, I didn't know you could use top level declarations for some functions, but not name the main function. Although I saw someone else do it, I find it somewhat disturbing. These days it works in GHCi at least.

Jelly, 13 bytes
⁶ṁ;@µḣJUz⁶ŒBY

Try it online!
How?
⁶ṁ;@µḣJUz⁶ŒBY - Main link: string s
⁶             - space character
 ṁ            - mould like s: len(s) spaces
  ;@          - concatenate s with that
    µ         - monadic chain separation (call that t)
      J       - range(length(t))
     ḣ        - head (vectorises): list of prefixes from length to all
       U      - upend: reverse each of them
        z     - transpose with filler:
         ⁶    -     space: now a list of the left parts plus centre
          ŒB  - bounce each: reflect each one with only one copy of the rightmost character
            Y - join with line feeds
              - implicit print

Alike minds think great. :P

Oh my I didn't think about a cumulative concatenation! Charcoal has a V direction, maybe some investigation thereabouts...

PHP, 95 92 85 80 78 77 bytes
Note: uses IBM-850 encoding
for($s.=strtr($s^$s=$argn,~ ,~▀);~$s[$i++];)echo$s,strrev($s=" $s"^$s^$s),~§;
          # Note that this ^ char is decimal 255 (negating it yields "\0")

Run like this:
echo "Hello" | php -nR 'for($s.=strtr($s^$s=$argn,"\0",~▀);~$s[$i++];)echo$s,strrev($s=" $s"^$s^$s),~§;'
> Hello         olleH
>  Hello       olleH
>   Hello     olleH
>    Hello   olleH
>     Hello olleH
>      HellolleH
>       HellleH
>        HeleH
>         HeH
>          H

Explanation
for(
  $s.=strtr(             # Set string to the input, padded with spaces.
    $s^$s=$argn,         # Input negated with itself, leads to string with
                         # only null bytes with the same length.
    ~ ,                  # Replace null bytes...
    ~▀                   # ... with spaces.
  );
  ~$s[$i++];             # Iterate over the string by chars, works because
                         # there are just as many lines as the padded
                         # string has chars.
)
  echo                   # Output!
    $s,                  # The string.
    strrev(              # The reverse of the string.
      $s=" $s"^$s^$s     # After each iteration, prefix string with a
    ),                   # space, and trim the last character.
    ~§;                  # Newline.

Tweaks

Saved 3 bytes by getting rid of the pad character (str_pad defaults to space, which is what we need)
Saved 7 bytes by using binary operations on the string to truncate it instead of substr
Saved 5 bytes by rotating the string when printing the reverse. Prevents the need for printing a backspace, but results in a trailing space on each line.
Saved 2 bytes by padding string using a more convoluted, but shorter method.
Saved a byte due to the fact that there is no need to account for the ~"0" case (ASCII 207), as all input may be assumed to be printable ascii (Thx @Titus)

echo$s,strrev($s=" $s"^$s^$s),~§; saves 5 bytes.

@Titus, thx. Usually I avoid trailing whitespace, but OP said it's acceptable

~$s[$i++] is sufficient (input is printable ASCII, and so is $s)

@Titus, thx, good catch. I tend to code on the safe side

MATLAB (R2016b), 223 183 bytes
r=input('');l=nnz(r)*2;for i=1:l;m=l+1-2*i;c={' '};s=cell(1,i-1);s(:)=c;x=cell(1,m);x(:)=c;e=r;y=flip(r);if(m<1);e=r(1:2*end-i+1);y=r(l/2+end-i:-1:1);end;disp(cell2mat([s e x y]));end

First time Code Golfing. Tips are welcome!
Program Output:

Edit:
Saved 40 bytes thanks to Luis Mendo.

Welcome to PPCG, and nice first answer! Unfortunately I know nothing about MATLAB so I'm not able to help you golf this, but perhaps you will find some of the tips helpful :-)

Inputting a string including its enclosing quotes is allowed by default. So you can remove 's' from input. Also, I don't see why you are using evalc(disp(...)), but I think you can just use cell2mat this way

Also, flip is shorter than end:-1:1, see here

Ruby, 85 83 bytes
edit: removed excess whitespace
s=ARGV[0];s+=' '*s.length;s.length.times{|i|puts s+s[i..-2].reverse;s=' '+s[0..-2]}

I actually found it pretty difficult to golf this one down in Ruby.  After adding whitespace, it expands to a pretty readable snippet of code:
s = ARGV[0]
s+=' ' * s.length

s.length.times do |i|
  puts s + s[i..-2].reverse
  s = ' ' + s[0..-2]
end

You could probably save a bit by setting s.length to a variable like I did? Also, I think you should consider doing size instead of length?

Doing what @user3334690 suggested and moving the .times statement, 79 bytes: s=ARGV[0];(s+=' '*s.size).size.times{|i|puts s+s[i..-2].reverse;s=' '+s[0..-2]}

You can save five bytes by making this a lambda.

Vyxal, 21 bytes
Ld(n⁰n⁰Ldεwi꘍⁰Ln-꘍øm,

Try it Online!
This was interesting. Here's a bugged version.
Ld(                   # Length * 2 times do...
   n                  # Iteration number...
            ꘍         # Spaces, plus...
    ⁰                 # Input string...
          wi          # Sliced to first...
         ε            # Absolute difference of...
     n                # Iteration number...
         ε            # And...
        d             # Double...
      ⁰L              # The original string's length...
                ꘍     # Plus...
               -      # Difference of...
            ⁰L        # Original string's length
               -      # And...
              n       # Iteration number
                ꘍     # Spaces.
                 øm   # Palindromised
                   ,  # And outputted.

Vyxal C, 5 bytes
L꘍¦Ṙʁ

Try it Online!
Less than half the bytecount of Jelly and 05AB1E, and less than a fourth of the bytecount of emanresu's Vyxal! evil laugh
L꘍¦Ṙʁ
 ꘍    # Append as many spaces to the input as...
L     # Its length
  ¦   # Get all prefixes of this
   Ṙ  # Reverse this
    ʁ # Palindromize each (for each x, x + x[::-1][1:])
      # C flag centers and joins on newlines

Think I'm cheating with flags?
Vyxal, 6 bytes
L꘍¦Ṙøṗ

Try it Online!
L꘍¦Ṙøṗ
 ꘍     # Append as many spaces to the input as...
L      # Its length
  ¦    # Get all prefixes of this
   Ṙ   # Reverse this
    øṗ # Palindromize each (for each x, x + x[::-1][1:]), center, and join on newlines

Holy frick I'm actually good at language design!

PowerShell, 126 bytes 124 bytes
$l=($s="$args")|% Le*;$r=-join$s[-1..-$l];0..($l*2-1)|%{' '*$_+($s+' '*$l).substring(0,$l*2-$_)+(' '*$l+$r).substring($_+1)}

Call it with a single parameter, such as .\V.ps1 Hello.
Edit: 2 bytes saved with tip from AdmBorkBork

A Try it online! link, in case you're interested.

Oh I didn't know about that little tool, thanks!

Hi there! A couple small golfs on the front. Take the input as a string, and use encapsulation to pass the variable along. Saves two bytes. $l=($s="$args")|% Le*;

Wow, didn't know about those 2 golfs, thanks!

JavaScript (ES6), 169 157 bytes
(-10 bytes thanks to Conor O'Brien)
V=(j,i=0,p="")=>i<(f=j.length)*2?V(j,-~i,p+" ".repeat(i)+j.slice(0,f-i*(i>f))+" ".repeat(i<f?(f-i)*2-1:0)+[...j.slice(0,f+~i*(i>=f))].reverse().join``+`
`):p

A recursive solution. I am new to JavaScript, so please be gentle! Any golfing tips are greatly appreciated. :)
And, of course, a very happy birthday to you V!
Test Snippet

V=(j,i=0,p="")=>i<(f=j.length)*2?V(j,-~i,p+" ".repeat(i)+j.slice(0,f-i*(i>f))+" ".repeat(i<f?(f-i)*2-1:0)+[...j.slice(0,f+~i*(i>=f))].reverse().join``+`
`):p
<input oninput=o.textContent=V(this.value)><pre id=o>

This is pretty good! Usually, s.split("") can be changed to [...s], and a.join("") can become a.join followed by a pair of backticks. You can save an additional 3 bytes by replacing [r='repeat'] and [r] with plain ol' repeat, same with slice.

@ConorO'Brien Thanks for the tips! They are much appreciated. :)

PowerShell, 88 86 80 76 bytes
param($n)0..($l=$n.length*2-1)|%{-join((" "*$_+$n+" "*$l)[0..$l+($l-1)..0])}

Try it online!
Happy Birthday, V!
This takes the input $n, then we loop from 0 up to 2 * $length - 1. Each iteration, we slice into (pre-pended spaces + $n + appended spaces) from 0 up to the last character, and then back down to 0. That's -joined together into a string and left on the pipeline.
All those strings are gathered from the pipeline, and an implicit Write-Output happens at program completion with a newline in between elements.
Golfed 6 bytes by eliminating $b. Golfed another four by redoing $n calculations.

CJam, 26 bytes
Happy birthday from your old pal CJam!
q_,2*:L,\f{LS*+m>L<_W%(;N}

Try it online!
Explanation
q                           Push the input
 _,2*:L                     Push 2 times the length of the input, store it in L
       ,                    Take the range from 0 to L-1
        \                   Swap top stack elements
         f{                 Map over the range, using the input as an extra parameter
           LS*+               Append L spaces to the input
               m>             Rotate the resulting string right i positions (where i is the
                               current number being mapped)
                 L<           Take the first L characters of the string
                   _W%        Duplicate it and reverse it
                      (;      Remove the first character from the copy
                        N     Add a newline
                         }  (end of block)
                            (implicit output)

Pyke, 14 bytes
l}j Fd*R+j^j<s

Try it online!

JavaScript (ES6), 94 bytes
f=(s,y=0,x=0,l=s.length*2-1)=>(s[(x>l?l*2-x:x)-y]||' ')+(x<l*2?f(s,y,x+1):y<l?`
`+f(s,y+1):'')

Test cases

f=(s,y=0,x=0,l=s.length*2-1)=>(s[(x>l?l*2-x:x)-y]||' ')+(x<l*2?f(s,y,x+1):y<l?`
`+f(s,y+1):'')

console.log(f('Happy'))
console.log(f('Birthday'))
console.log(f('V!'))
console.log(f('~'))

J, 44 Bytes
(([(,}.@|.)@{."1-@i.@[|."0 1(,#&' ')~)~+:@#)

Hmm, I can't figure out how to run this online. Try it online! Am I just calling it wrong? (I'm a J newb)

@DJMcMayhem That's a function, not a program. https://tio.run/nexus/j#@5@mYGuloKERraFTq@dQo6fpUK2nZKjrkKnnEF2jp2SgYKiho6ymrqCuWadZp23loKzJlZqcka@QpqDukZqTk6/@/z8A

Golf: |."0 1 to |."{ (saved 2 bytes)

Also, you don't have to have the outer parentheses.

Perl 5, 58 + 1 (-n) = 59 bytes
$_.=$"x(($l=2*y///c)+3).reverse;say while s/(.{$l})../ $1/

Try it online!

Mathematica (101 bytes)
Happy birthday to V from Mathematica!
Anonymous function, takes input as a string.
""<>NestList[" "<>StringDrop[#,{n,n+1}]&,#<>{" "~Table~{n=2StringLength@#-1},StringReverse@#,"
"},n]&

The newline is meant to be there.
Explanation: First, we generate the top line by joining the input, 2m-1 spaces (where m is the length of the input), the input reversed, and a newline. Then, each line is the previous one without the (2m-1)th and (2m)th characters, with a space added to the start.

Perl, 71 + 5 (-nlaF flag) = 76 bytes
Based on Dom Hastings solution.
push@F,($")x@F;print$"x$_,@F[0..$#F-$_],reverse@F[0..@F-$_-2]for 0..$#F

Try it online.
Perl, 81 + 5 (-nlaF flag) = 86 bytes
Previous version.
@F=(@s=(' ')x($l=@F*2),@F,@s);say@h=@F[-$_..$l-$_-1],reverse@h[0..@h-2]for-$l..-1

Try it online.

Hey, I made a slightly smaller version (81 bytes with print and same flags) It uses pretty much the same method as yours though: Try it online!

@DomHastings -4 bytes.

Amazing, good going!

Pyth, 22 bytes

+Rt_dm<+*;d+Q*lQ;ylQyl

     m              yl for d from 0 to double of length of input (exclusive)
                ;          space character
             *lQ           repeat as many times as length of input
           +Q              prepend input
       +*;d                prepend space repeated as many times as d
      <          ylQ       extract first (input length doubled) characters
 R                     for each string d obtained above
+                          append
  t_d                      tail of reverse of d (tail means d[1:])

Try it online! (a j is prepended to the code to make the output more beautiful)

SmileBASIC, 131 127 125 109 105 91 85 84 bytes
Possibly some room for improvement here...
LINPUT S$K=LEN(S$)*2FOR J=1TO K
FOR I=1-K TO K?(" "*J+S$+" "*K)[K-ABS(I)];
NEXT?NEXT

Explanation:
(Input=V!)
The program uses k-ABS(x-k)-y (where k=length*2-1) to convert a position to a number:
 0 1 2 3 2 1 0
-1 0 1 2 1 0-1
-2-1 0 1 0-1-2
-3-2-1 0-1-2-3

To get rid of negative numbers, k is added:
3 4 5 6 5 4 3
2 3 4 5 4 3 2
1 2 3 4 3 2 1
0 1 2 3 2 1 0

Now we can just uses these as indexes into the input string, padded with k spaces on each end (...V!...).
V ! . . . ! V
. V ! . ! V .
. . V ! V . .
. . . V . . .

Ruby, 70 bytes
I wasn't sure I could beat the other Ruby submissions, but I managed to do it. Those last three lines are killing me, though.
->s{z=s.size*2-1
s+=" "*z+s.reverse
z.times{s[z,2]=""
puts s
s=" "+s}}

Try it online!

Julia, 88 86 bytes
w=" ";a%b=b<w?a:a*b*(w*chop(a)%b[2:end]);!r=r[1:(n=end)]*w^n%(w^(n-1)*reverse(r)*"\n")

Explained:
#Assign space char to w.
w=" ";

#Redefine modulo operator so it is a V generator:
#In the base case (when b is lexographically before a space, which
#occurs when b consists of a newline), print a.
#In the recursive case, concatenate a, b and the result to a recursive
#call with arguments consisting of a shifted right, and b shifted
#left.
a%b=b<w?a:a*b*(w*chop(a)%b[2:end]);

#Frontend function for the V-generator, which automatically feeds the
#V-generator with the correct arguments.
!r=r[1:(n=end)]*w^n%(w^(n-1)*reverse(r)*"\n")

Canvas, 8 bytes
ｌ«＊＼ｌｍ││

Try it here!
Explanation:
l         push length of input
 «        multiply by 2
  *       push an array of the input repeated that many times
   \      pad with a space triangle
    l     push the height of that
     m    and mold the width to that, discarding anything after
      ││  palindromize horizontally

05AB1E, 11 10 bytes
-1 byte thanks to steffan.
ðs∍«η€ûR.C

Try it online!
ðs∍«η€ûR.C  # full program
        .C  # push centered lines of...
       R    # reversed list of...
     €û     # palindromized...
    η       # prefixes of...
  ∍         # length of...
 s          # implicit input...
ð           # spaces...
   «        # concatenated to...
            # implicit input
            # implicit output

You don't need the » near the end.

Charcoal, 23 bytes
Ａ×²ＬθαＦθ«Ｐ↘…ια→Ａ⁻α¹α»‖Ｂ

Try it online!
This just draws lines downrightwards with the characters of the input and then reflect the canvas horizontally (skipping the central line). Verbose version here.
Charcoal, 26 bytes
Ａ×²ＬθαＦθ«ＧＨ>αιＭ⁻×²α³→Ａ⁻α¹α

Try it online!
This answer just draws consecutively smaller "V"-shaped polygons using the characters in the input. Verbose version here.

The requirement to mark newer languages/features as non-competing has recently been abolished.

@ØrjanJohansen I didn't know it, thanks!

You need to use ReflectOverlap because ReflectBufferfly switches bs and ds. I golfed @DLosc's solution down to 17 bytes using just features available at the time, but I can do it in 16 bytes now.

Stax, 10 bytes
ßë♠♂æÄ|Åò▓

Run and debug it

Excel, 125 bytes
=LET(n,LEN(A1),y,SEQUENCE(1,4*n),z,2*n-ABS(2*n-y)+1-SEQUENCE(2*n),m,IF((z>0)*(z<=n),MID(A1,z,1)," "),CONCAT(IF(y=4*n,"
",m)))

Try it online

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

sort: votes